• Elasticsearch笔记


    拉呱,无论是当作全文检索工具,还是仅仅当作NOSQL,Elasticsearch的性能,牛的没法说!!!奈何和它相见恨晚

    点击进入官网

    中文文档

    一. 使用场景

    • 全文检索-像淘宝京东类似的网上商城,当我们在在搜索框搜索某个商品名称时,网络没有问题的话,获取响应的速度,几乎和我们键盘起落的速度是一致的,这足以ES的魅力,亿万级别的搜索,秒秒钟完事

    • 一个正规的项目运行过程中,日志的产出是源源不断的,把日志的文本信息导入到ES,使用它的聚合功能轻松获取我们关系的内容,结合Kibana做图表分析,可视化日志记录,动态分析

    二. 基本概念

    • 2.1 什么是是全文检索
      全文检索就是计算机程序通过扫描文章中的每一个词,对必要的词建立一个索引(上篇博客我们使用ik分词器,帮助es分词),记录下这个词在文章中出现的位置和次数,这样当用户去查询的时候,他可以根据索引极快的查找出相应的内容

    稍微解释下, 全文检索可以片面的理解成是从敲代码的人的角度上说的,假如你是用户,你会关心什么全文检索? 用户关系的是搜索结果!那好,对我们敲代码的来说,就是1.拿到用户搜索框输入的关键字送进ES (数据在存进es的时候,es对他们进行了索引)2.ES的程序会对关键字进行分词,拿着这些碎片去ES中的索引库里面的type中的field中匹配比对,那,那么多field,它和谁比对呢? 和标记上text属性的字段比对)

    另外要了解的内容1.全文检索只处理文本不处理语义,2.全文检索忽略英文的大小写 3.结果可能不止一个,并且有相关得分

    • 2.2 与关系型数据库名称上的对比
    mysql Elasticsearch
    Database 数据库 indices 索引
    Table 数据表 type 类型
    Row 行 document 文档
    Columns 列 Field 字段

    其实大多数人都是先接触的关系型数据库,我也是,可能一开始感觉着好别扭,但是再回头来看,好像他的名字比传统的关系型数据库名什么行啊列啊,更合理一些

    • 2.3 分片(shard)和副本(replica)

    单机

    通过图片可以看到: 数据分成三部分,分别存放在三个分片里面,而且每个分片都有自己的副本,这样就算是一台es,它同样是分布式

    二. 怎么玩?

    这部分纯属扯皮了,不说语法,说一下我对它的感觉,首先呢, 为什么学它? 图方便快速呗,大部分情况下,是需要使用它的全文检索功能,但是总得有个下手点吧,不用说一开始都是环境配置一顿整,访问个9200看到版本号,也算是开个头了,然后呢? 先不用想他怎么检索,怎么花里胡哨的检索,我们得知道自己想检索什么!先把数据给它,思路就来了,先去搞数据,下一步自然就是创建新的索引(数据库),循环把我们的数据送进es的索引里面.到这里,也算是完成一半的任务了,下面就是使用人家提供好的api去索引库,检索就好了. 先有个大概的思路.想干什么,怎么干,往下学

    三. 原生语法

    • elasticsearch采用的REST风格的api,也就是说,其实他就是一次http的请求

    下面会有一些关键字 也就是json的 key部分,对我们来说,一般可以见名知意

    3.1.1 创建索引库

    • 请求方式: PUT
    • 请求路径: /索引库名
    • 请求参数: json
    PUT /xiaowu1
    {
      "settings": {
        "number_of_shards": 1
        , "number_of_replicas": 1
      }
    }
    

    成功的相应:

    {
      "acknowledged": true,
      "shards_acknowledged": true,
      "index": "xiaowu1"
    }
    

    3.1.2 查看数据库

    • 请求方式: GET
    • 格式: GET /索引库名
    GET /xiaowu1
    

    响应:相关的源信息

    {
      "xiaowu1": {
        "aliases": {},
        "mappings": {},
        "settings": {
          "index": {
            "creation_date": "1552653562807",
            "number_of_shards": "1",
            "number_of_replicas": "1",
            "uuid": "u0tMDD-pQXaHb77cTPorZA",
            "version": {
              "created": "6020499"
            },
            "provided_name": "xiaowu1"
          }
        }
      }
    }
    

    3.1.3 删除索引库

    • 请求方式: DELETE
    • 格式: DELETE /索引库名

    3.2.1 配置映射

    在玩搜索之前我们要思考如何定义文档的,如文档包括哪些字段,这些字段是否保存,是否索引,是否分词等等, 实际上就像是在描述我们数据库中的一张表,有哪些列,列是什么类型的,是主键不?自增长不?

    以后看到"mappings":{} 就像查看关系型数据库中对整张表的定义一样

    • 请求方式: PUT
    • 格式: PUT /索引库名/_mapping/类型名
    PUT /xiaowu/_mapping/goods
    {
      "properties": {      ---属性关键字
        "name":{           ---name为字段名,可以不止一个,就像数据库中的列,你开心,多少个都行
          "type": "text",  ---类型常用:integer,long,text,object,date,short,string,float 
          "index": true,   ---是否索引  默认true
          "store": false,   ---是否存储  默认false
          "analyzer": "ik_max_word" ---是否分词
        },
         "images": {
          "type": "keyword",  
          "index": "false"
        },
        "age": {
          "type": "float"
        }
      }
    }
    

    1 .字符串类型有两种

    • text : 可检索
    • keyword : 不可检索

    2 .数值类型

    • 基本数值类型: long ,float,byte,double...
    • 浮点数高精度类型: scaled_float
      • 它需要我们指定一个精度因子,比如10,100,es把真实值乘以这个精度因子存储,取出后还原,(商品价格)
    1. 日期类型:
    • Date
    1. 存储对象
    {girl:{name:"张三",age:23}
    

    而是会把它处理成 girl.namegirl.age

    5 .store

    • 表示,是否将数据额外存储,意思是,如果不存储,用户就搜索不出来
    • 在solr中如果为store设为false,那么用户就搜索不出来这个字段
    • 但是elasticsearch中,并不用store的值控制是否可以被搜索出来,即便他是false,用户仍然可以搜索出结果,原因是elasticsearch的底层,在创建文档时,会将文档的原始数据备份保存到一个叫 _source的属性中,而我们可以通过过滤_source选择那些需要显示,那些不需要显示,这样如我们把store的值设置为ture它就会多储存一份,得不偿失(store相当于作废了)

    3.2.2 向已经存在的索引库中添加数据(不一定要指定ID)

    • 请求方式: POST
    • 格式: POST /索引库名/类型名{}
    POST /changwu/item/
    {
        "title":"小米手机",
        "price":2699.00
    }
    

    响应:

    {
      "_index": "changwu",
      "_type": "item",
      "_id": "Pj6bgWkB3eQnUSvRfoa2",
      "_version": 1,
      "result": "created",
      "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
      },
      "_seq_no": 5,
      "_primary_term": 6
    }
    

    id,是自动生成的当前数据的标识,我们还可以指定

    POST /changwu/item/2
    

    3.2.3 基本查询

    • 请求方式: GET
    GET /索引库名/_search
    {
      "query": {
        "查询类型":{
          "查询条件": "条件值"
        }
      }
    }
    
    • query是Elasticsearch内置的一个对象,里面有不同的查询属性

    使用,SpringDataElasticsearch玩复杂查询的时候,免不了会BuildQueryXXX

    • 查询类型:
      • match_all 查询所有
      • match
      • term
      • range
    • 查询条件根据类型的不同而不同,(就像关系型数据库中表的字段不同...)

    3.2.4 匹配查询 match

    or 关系

    match类型查询,会把查询条件进行分词,然后再查询,词条之间是or关系,按照相关性得分排序

    GET /goods/_search
    {
      "query": {
        "match":{
          "price": 269900
        }
      }
    }
    

    and关系

    很多情况下我们希望更精确的查找,于是我们使用 and关系

    GET /xiaowu/_search
    {
         "query":{
           "match":{
             "title":{
                "query":"米手机",
                "operator":"and"
             }
           }
         }
    }
    

    这样他在分词的时候,米--手机同时都匹配上才会显示出结果!

    假设有这样一种情况,用户给定的条件分词后,有五个词,但是其中的四个是在描述他想要搜索的内容,如果使用or,毫无疑问,一大堆杂七杂八的东西被查询出来,如果使用and,es很可能把那个目标文档排除,那该怎么办呢?看下面!

    • match支持使用minimum_should_match 最小匹配参数,通常设置为一个百分数
    GET /xiaowu/_search
    {
         "query":{
           "match":{
             "title":{
                "query":"米手机",
                "minimum_should_match":"75%"
             }
           }
         }
    }
    

    意思是,用户输入的词条满足75%的匹配程,我就认为是匹配上了, ---用户输入的检索条件,被分解为三个词,3*0.75=2.25 也就是说,这三个词,至少有两个是匹配上的,es就认为匹配成功

    3.2.5多字段查询 muti_match

    • muti_match和match一样,但是不同的是它可以同时在多个字段中检索
    GET /xiaowu/_search
    {
         "query":{
           "multi_match":{
                "query":"米",
                "fields":["title"]
           }
         }
    }
    

    他的fields接受一个字段数组

    3.2.6 词条查询(term)

    • 和前面的查询条件不同的是term,它被用作精确查询,比如数字,时间,布尔,和字段属性为keyword类型的关键字
    GET /xiaowu/_search
    {
       "query": {
         "term": {
           "price": {
             "value": "1888"
           }
         }
       }
    }
    

    3.2.7 多词条精确匹配

    • 和term一样的精确匹配,但是不同的是它支持同时使用多个词条进行精确匹配,如果只要索引库中的文档包含指定值中的任意一个,都算作满足条件

    3.3.1 结果过滤

     默认情况下,elasicsearch在搜索的结果在,会把文档保存在_source里面的所有字段都返回,如果我们想获取里面的部分结果,添加_soure过滤

    GET /xiaowu/_search
    {
      "_source": ["过滤字段"], 
       "query": {
         "term": {
           "price": {
             "value": "1888"
           }
         }
       }
    }
    
    • 另外,_source里面还有两个属性
      • "includes":[想显示的字段]
      • "excludes":[不想显示的字段]

    解读查询结果:

    {
      "took": 1,    ----花费时长,单位毫秒
      "timed_out": false,  ----是否超时
      "_shards": {      --- 分片信息
        "total": 1,    
        "successful": 1,
        "skipped": 0,
        "failed": 0
      },
      "hits": {     --- 命中的结果
        "total": 1, --- 结果总数
        "max_score": 4.765019, ---相关性的最高得分
        "hits": [      --- 搜索结果的对象数组
          {
            "_index": "goods",   ---  索引
            "_type": "docs",     --- 类型
            "_id": "180",        ---  唯一id
            "_score": 4.765019,  ---文档得分
            "_source": {            --- 文档的数据源,(前面说过,结果都在_source里面)
              "id": 180,
              ...
              }
    
    • 在所有的index里面查询指定的字段
    GET _search
    {
      "query": {
       "match": {
         "title": "小米2手机"
       }
      }
    }
    

    3.4.1 智能判断

    • 新增属性的时候,可以添加新的字段
    POST /xiaowu/goods/
    {
      "title":"es666",
      "hehe":true
      
    }
    

    查询结果:

    {
            "_index": "xiaowu",
            "_type": "goods",
            "_id": "Qz69gWkB3eQnUSvRC4ah",
            "_score": 1,
            "_source": {
              "title": "es666",
              "hehe": true
            }
    

    查看映射

    {
      "xiaowu": {
        "mappings": {
          "goods": {
            "properties": {
              "age": {
                "type": "float"
              },
              "hehe": {
                "type": "boolean"
              },
              "images": {
                "type": "keyword",
                "index": false
              },
              "name": {
                "type": "text",
                "store": true,
                "analyzer": "ik_max_word"
              },
              "price": {
                "type": "float"
              },
              "title": {
                "type": "text",
                "fields": {
                  "keyword": {
                    "type": "keyword",
                    "ignore_above": 256
                  }
                }
              }
            }
          }
        }
      }
    }
    

    这样看,其实我们在上面配置的映射关系就没有必要了,Elasticsearch会智能化的推断出字段的type,比如true它推断为boolean, 但是有问题的是title 它推断为 text ,title.keyword是 keyword类型

    3.5.1 修改数据(指明ID)

    把上面的POST转变成PUT就是修改

    • id对应的文档存在则修改
    • id对应的文档不存在则新增

    3.6.1 删除数据

    语法: DELETE /索引库名/类型名/id

    3.7.1 高级玩法-布尔组合

    看得懂,会使用Elasticsearch的高级玩法很重要,这关系着,能不能理解如何使用它的原生api进行高级查询

    • 布尔组合,结合了其他的查询,实现了这样的功能, -- 我的搜索结果中,一定含有谁(must),一定不含有谁(must_not),可能含有谁(should)
    GET /xiaowu/_search
    {
      "query": {
        "bool": {
          "must": [
            {
              "match": {
                "title": "米"
              }
            }
          ],
          "must_not": [
            {
              "match": {
                "title": "大"
              }
            }
          ],
         "should": [
           {
             "match": {
               "price": "999"
             }
           }
         ]
        }
      }
    }
    

    3.7.2 高级玩法--范围查询range

    • range实现的是查询出满足某个区间的结果
    GET /xiaowu/_search
    {
      "query": {
        "range": {
          "FIELD": {
            "gte": 10,
            "lte": 20
          }
        }
      }
    }
    
    关键字 含义
    gte 大于等于
    lte 小于等于
    gt 大于
    lt 小于

    3.7.3 模糊查询---fuzzy

    模糊查询很人性化,它允许用户在编辑的条件有拼写错误,但是出现偏差的编辑差距不得超过2

    GET /xiaowu/_search
    {
      "query": {
        "fuzzy": {
          "title": {
           "value": "appla",
           "fuzziness": 1
           }
        }
      }
    }
    
    • 这样查询是可以查询出apple的
    • "fuzziness": 限定编辑距离

    3.7.4 过滤---filter

    • 1.有条件查询进行过滤

    查询就会影响文档的相关性得分,假如我们只是想在现有的查询基础上,根据需求过滤下一些结果,却不想影响文档的相关性得分的话filter就派上用场了

    GET /changwu/_search
    {
        "query":{
            "bool":{
            	"must":{ "match": { "title": "小米手机" }},
            	"filter":{
                    "range":{"price":{"gt":2000.00,"lt":3800.00}}
            	}
            }
        }
    }
    

    filter中还可以在bool组合过滤

    • 2.无条件查询进行过滤

    如果一次查询只有过滤,没有查询条件,不希望进行评分,我们可以使用constant_score

    GET /changwu/_search
    {
        "query":{
            "constant_score":   {
                "filter": {
                	 "range":{"price":{"gt":2000.00,"lt":3000.00}}
                }
            }
    }
    

    3.7.5 --- 排序 sort

    排序sort和query是有先后顺序的,先query,再排序

    • 单字段排序
    GET /changwu/_search
    {
      "query": {
        "match": {
          "title": "手机"
        }
      },
      "sort": [
        {
          "price": {
            "order": "asc"
          }
        }
      ]
    
    }
    
    • 多字段排序

    看上面的sort后面的条件,是个数组,因此我们可以写条件,按多个字段进行排序


    聚合:aggregations

    • 基本概念,两个新概念,在Elasticsearch中的聚合分为两个部分,聚合为 桶bucket度量
      • 桶就像mysql中的分组查询,比如说学号相同,姓名相同的肯定是同一个人,我们就把它当成一组,在这里就是一个桶
      • 度量--以每个桶为基础,做运算

    当然Elasticsearah里面分桶的方式很多

    • Terms Aggregation:根据词条内容分组,词条内容完全匹配的为一组
    • Range Aggregation:数值和日期的范围分组,指定开始和结束,然后按段分组,这个范围要手动告诉他,0-10 10-15 15-30等
    • Histogram Aggregation:根据数值阶梯(柱状图)分组,与日期类似, 告诉他一个段就行了,她会自动的分组
    • Date Histogram Aggregation:根据日期阶梯分组,例如给定阶梯为周,会自动每周分为一组

    常用的度量方法:

    • Avg Aggregation:求平均值
    • Max Aggregation:求最大值
    • Min Aggregation:求最小值
    • Percentiles Aggregation:求百分比
    • Stats Aggregation:同时返回avg、max、min、sum、count等
    • Sum Aggregation:求和
    • Top hits Aggregation:求前几
    • Value Count Aggregation:求总数

    es中进行过滤,排序,聚合的字段,不能被分词!!!!*

    GET /cars/_search
    {
      "size": 0,
      "aggs": {
        "popular_brand": {
          "terms": {
            "field": "color"
          },
          "aggs": {
            "priceAvg": {
              "avg": {
                  "field": "price"
              }
            }
          }
        }
      }
    }
    

    一般都是先聚为桶,然后在桶的基础上进行度量

    四.SpringDataElsticsearch

    SpringDataElasticsearch官方文档地址

    2.png

    这是原来画的图,JEST直接放弃了,让我们自己拼接json串,简直只有难受

    终于到编码阶段,这部分相比前面的原生api看起来就好受多了,Spring一整合,啥东西都简单的只剩下两件事,1,写个配置文件,2.用它的方法,玩他的注解--, 当然我现在回顾学习的整个过程,最重要的是还是那句话,不要忘记了自己的需求,不然学着学着容易迷失,不知道自己想干啥,对于Elasticsearch吧先觉的它啥都能干,又觉得它啥也干不了,这是个很尴尬的事情! 那,我用它做全文检索,我就得去搞明白 知道下面那几件事

    1. 怎么搭建起开发环境,使我的java代码和ES交互
    2. spring整合它嘛,提供了哪些注解,表示我的javaBean是个document对象
    3. 如何建立索引库
    4. 基本的CRUD
    5. 花里胡哨的查询方法

    下面挨个做这几件事!

    4.1 搭建开发环境

    坐标

     <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    </dependency>
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    

    配置文件(java和它的交互走的是tcp协议)

    spring:
      application:
        name: search-service
      data:
        elasticsearch:
          cluster-nodes: 192.168.43.150:9300
          cluster-name: elasticsearch
    

    启动类

    4.1 实体类及注解

    实体类在java中就像是接盘侠,啥样的东东,它都有能给接下来,看完了下面的注解,就知道了如何把数据存进es认识的实体类,准备把他们存在索引库

    import org.springframework.data.annotation.Id;
    import org.springframework.data.elasticsearch.annotations.Document;
    import org.springframework.data.elasticsearch.annotations.Field;
    import org.springframework.data.elasticsearch.annotations.FieldType;
    
    
    @Data
    @Document(indexName="changwu",type = "item",shards = 1)
    public class Item {
    
        @Id
        @Field(type=FieldType.Long)
        Long id;
    
        @Field(type = FieldType.Text,analyzer = "ik_smart")
        String title; //标题
    
        @Field(type=FieldType.Keyword,index = true)
        String category;// 分类
    
        @Field(type=FieldType.Keyword)
        String brand; // 品牌
    
        @Field(type=FieldType.Double)
        Double price; // 价格
    
        @Field(type=FieldType.Keyword,index = false)
        String images; // 图片地址
        
        // 指定存储时和检索时使用的分词器是同一个
        // index=true 表示索引
        // 是否索引, 就是看这个字段是否能被搜索, 比如: 如果对整篇文章建立了索引,那么从文章中任意抽出一段来,都可以搜索出这个文章
        // 是否分词, 就是表示搜索的时候,是整体匹配还是单词匹配  比如: 如果不分词的话,搜索时,一个词不一样,都搜索不出来结果
    
        // 是否存储, 就是,是否在页面上展示 , 但是在es中默认字段值已经存储在_source 字段里, 也是能检索出原始字段的
        @Field(index = true, store = true,type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_max_word")
        private String title;
    
        /**
         * analyzer 存进去的时候,按这个分词
         * searchAnalyzer: 搜索时,按这个分词
         */
        @Field(index = true, store = true, type = FieldType.Text ,analyzer = "ik_max_word", searchAnalyzer = "ik_max_word")
        private String content;
    
        @Field(index = true,type = FieldType.Keyword)
        private String state;
    
    }
    
    
    • @Document
    1. 作用在类,标记实体类为文档对象
      • indexName:对应索引库名称---- 数据库名
      • type:对应在索引库中的类型---- 表名
      • shards:分片数量,默认5
        -replicas:副本数量,默认1
    • @Id
    1. 作用在成员变量id上
      • 标记一个字段作为id主键(这个id别写错了,不然程序都启动不起来)
    • @Field
    1. 作用在成员变量,标记为文档的字段,并指定字段映射属性:
      • type:字段类型,取值是枚举:FieldType
      • index:是否索引,布尔类型,默认是true
      • store:是否存储,布尔类型,默认是false
      • analyzer:分词器名称

    另外不要忘记了它的智能推断,如果我们不在字段上添加@Field,他根据值的类型进行推断

    比如: 下面三个都会被推断为long类型,

    private Long cid3;//  
    private Date createTime;//  
    private List<Long> price;//  
    

    4.2 创建索引库

    索引库的创建放到text里面就ok了

    • 使用的是ElasticsearchTemplate,Spring一直都是这样,整合完了,给你个模板

    创建索引,添加映射,删除索引

    template.createIndex(Goods.class);
     
    template.putMapping(Goods.class);
    
    template.deleteIndex()
    

    4.3 基本的CRUD

    SpringData的强大之后就是,我们不再去写dao层了,她会通过反射给我们写好,有点Mybatis里面的通用mapper的意思,但是它更强大,---你给方法名它自动的生成方法

    public interface GoodsRepository extends ElasticsearchRepository<Goods,Long> {}
    

    使用 repository点一下,findXX saveXXX, deleteXXX全出来了,不再细说

    另外:
    点击进入如何自定义方法,Spring给实现

    如果可以看懂原生的语法,那么对他的使用就不多说了...就是无脑使用

    到了这,就知道了如何把通过java代码,对索引库里面的数据进行简单的增删改查

    4.4 着重看一下如何进行繁杂查询

    真正使用es的时候,Repository里面的方法可以满足大部分的功能,但是聚合,过滤的话,只能使用原生的API

    假设我们有下面的需求: 前端把用户需要搜索的信息收集起来了--全文检索

    • 全文检索
    /**
     * 全文检索
     */
    @Test
    public void textQuery(){
    
        //创建查询构建器
        NativeSearchQueryBuilder QueryBuilder = new NativeSearchQueryBuilder();
    
        /**
         * 给查询构造器添加条件
         *   1. 它仍然需要的是一个  QueryBuilder ,通过QueryBuilders里面的静态方法创建,间接继承了QueryBuild
         *   2. 可也看到,基本上所有常用的条件查询都有了, bool , 词条term , match , 模糊查询 fuzzy
         *   3. 我们也可以抽出来一个方法, 方法里使用bool查询, 他支持先添加查询,紧接着过滤,  还记不记得那个  match{},filter:{}
         *    3.1 注意区分开结果过滤_source 和 filter
         *
         *         matchQuery     @Param field
         *         matchQuery     @Param field的值
         *   */
        QueryBuilder.withQuery(QueryBuilders.matchQuery("title","小米"));
    
        /**
         * 结果过滤
         * @Param : SourceFilter  ,但是它是和接口,于是我用它唯一的实现类
         */
        QueryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{"title","price"},null));
    
        /**
         * 排序
         */
        QueryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.ASC));
    
        /**
         * 分页
         *  原生的api使用下面两个字段控制
         *  "from": 0,
         *  "size":10
         *  但是注意,他是的第一页是0
         * @Param : Pageable 他是个接口,我们使用它的实现类  PageRequest(静态方法of)
         */
        QueryBuilder.withPageable(PageRequest.of(1,10));
    
        Page<Goods> result = repository.search(QueryBuilder.build());  //它仍然需要的是一个QueryBuilder , 通过构造器.build()构建出来
    
        //解析结果
        long elements = result.getTotalElements();
        int totalPages = result.getTotalPages();
        List<Goods> content = result.getContent();
    }
    
    
    /**
     * 创建基本的查询条件
     * 创建布尔查询,
     *  一部分当作查询条件(must)
     *  一部分当作过滤条件(filter)
     * @param searchRequest
     * @return QueryBuilder 给QueryBuild.withQuery()使用
     */
    private QueryBuilder buildBasicQuery(SearchRequest searchRequest) {
        //创建布尔查询
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        //查询条件
        queryBuilder.must(QueryBuilders.matchQuery("字段名",字段值));
    
        if(过滤条件){
        /*
        *把处理好的字段,传给过滤器 过滤
        *@param name  The name of the field
        *@param value The value of the term
        */ 
        queryBuilder.filter(QueryBuilders.termQuery(字段名,字段值));
        }
    return  queryBuilder;
    }
    
    
    
    • 聚合查询

    3.png

     /**
       * 聚合查询
       */
    @Test
    public void textAgg(){
    
        //同样少不了 查询构造器
        NativeSearchQueryBuilder QueryBuilder = new NativeSearchQueryBuilder();
    
        /**
         * 添加聚合add, 可以聚合多次
         * @Param AbstractAggregationBuilder 它间接继承与 AggregationBuilder 我们下面的工具类
         *
         * AggregationBuilders下面基本上涵盖了我们所有的聚合方式
         */
        QueryBuilder.addAggregation(AggregationBuilders.terms("popular_brand").field("brand"));
    
        /**
         * 推荐使用和这个,支持聚合查询,并返回带聚合的结果
         * @Param :SearchQuery
         * @Param :Class<T>
         * @Return:
         */
        AggregatedPage<Goods> result = template.queryForPage(QueryBuilder.build(), Goods.class);
    
        /**
         * 解析聚合
         *
         */
        Aggregations aggregations = result.getAggregations();
        // 获取指定名称 聚合
        //Aggregations agg = aggregations.get("popular_brand");
        StringTerms agg = aggregations.get("popular_brand");
    
        /**
         * 问题来了,  不存在 agg.getBuckets()
         * 原因看上面的图,是 Aggregations是个顶级接口,
         */
        List<StringTerms.Bucket> buckets = agg.getBuckets();
    
        //遍历buckets
        for (StringTerms.Bucket bucket : buckets) {
            System.out.println(bucket.getKeyAsString());
            System.out.println(bucket.getDocCount());
        }
    
    }
    
  • 相关阅读:
    Spring配置数据源和注解开发
    spring 的配置介绍
    spring
    maven
    mybatis初始
    idea中配置xml不自动提示解决方案(eclipse配置XmlCatalog)
    JSON、AJAX
    ThreadLocal的使用
    Filter过滤器
    谷歌 kaptcha 图片验证码的使用
  • 原文地址:https://www.cnblogs.com/ZhuChangwu/p/11150374.html
Copyright © 2020-2023  润新知