• ElasticSearch内容详讲


    一、概述

    Elasticsearch 是一个开源的搜索引擎,建立在一个全文搜索引擎库 Apache Lucene™ 基础之上。 Lucene 可以说是当下最先进、高性能、全功能的搜索引擎库—无论是开源还是私有。ES使用 Java 编写的,它的内部使用 Lucene 做索引与搜索。

    特点

    • 一个分布式的实时文档存储,每个字段 可以被索引与搜索
    • 一个分布式实时分析搜索引擎
    • 能胜任上百个服务节点的扩展,并支持 PB 级别的结构化或者非结构化数据

    非常好的教程推荐:https://www.tizi365.com/archives/590.html

    1.存储结构与数据类型

    类比MYSQL存储结构

    Elasticsearch存储结构MYSQL存储结构
    index(索引)
    Document(文档)行,一行数据
    Field(字段)表字段
    mapping (映射)表结构定义

    index(索引):相当于 mysql 的表

    Document(文档):相当于表中的每一条记录,这里都是json数据

    Field(文档字段):相当于表中的字段

    • 字符串:主要包括: text和keyword两种类型,keyword代表精确值不会参与分词,text类型的字符串会参与分词处理。
    • 数值:包括: long, integer, short, byte, double, float
    • 布尔值:boolean
    • 时间:date
    • 数组:数组类型不需要专门定义,只要插入的字段值是json数组就行。
    • GEO类型:主要涉及地理信息检索、多边形区域的表达,后面GEO相关的章节单独讲解

    mapping (映射):Elasticsearch的mapping (映射)类似mysql中的表结构定义,每个索引都有一个映射规则,我们可以通过定义索引的映射规则,提前定义好文档的json结构和字段类型,如果没有定义索引的映射规则,Elasticsearch会在写入数据的时候,根据我们写入的数据字段推测出对应的字段类型,相当于自动定义索引的映射规则。

    2.文档元数据

    文档元数据,指的是插入JSON文档的时候,Elasticsearch为这条数据,自动生成的系统字段

    元数据的字段名都是以下划线开头的。

    常见的元数据如下:

    • _index - 代表当前JSON文档所属的文档名字
    • _type - 代表当前JSON文档所属的类型,虽然新版ES废弃了type的用法,但是元数据还是可以看到。
    • _id - 文档唯一Id, 如果我们没有为文档指定id,系统会自动生成
    • _source - 代表我们插入进去的JSON数据
    • _version - 文档的版本号,每修改一次文档数据,字段就会加1, 这个字段新版的ES已经不使用了
    • _seq_no - 文档的版本号, 替代老的_version字段
    • _primary_term - 文档所在主分区,这个可以跟_seq_no字段搭配实现乐观锁。

    二、查询语法

    1.查询基本语法结构

    GET /{索引名}/_search
    {
    	"from" : 0,  // 返回搜索结果的开始位置
      "size" : 10, // 分页大小,一次返回多少数据
      "_source" :[ ...需要返回的字段数组... ],
    	"query" : { ...query子句... },
    	"aggs" : { ..aggs子句..  },
    	"sort" : { ..sort子句..  }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    query子句:主要用来编写类似SQL的Where语句,支持布尔查询(and/or)、IN、全文搜索、模糊匹配、范围查询(大于小于)。

    aggs子句:主要用来编写统计分析语句,类似SQL的group by语句

    sort子句:用来设置排序条件,类似SQL的order by语句

    分页:主要通过from和size参数设置,类似MYSQL 的limit和offset语句

    _source:用于设置查询结果返回什么字段,类似Select语句后面指定字段

    2.Query查询

    2.1匹配单个字段-match

    通过match实现全文搜索,全文搜索的后面有单独的章节讲解,这里大家只要知道简单的用法就可以。

    GET /{索引名}/_search
    {
      "query": {
        "match": {
          "{FIELD}": "{TEXT}"
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • {FIELD} - 就是我们需要匹配的字段名
    • {TEXT} - 就是我们需要匹配的内容

    2.2精确匹配单个字段-term

    如果我们想要类似SQL语句中的等值匹配,不需要进行分词处理,例如:订单号、手机号、时间字段,不需要分值处理,只要精确匹配。

    通过term实现精确匹配语法:

    GET /{索引名}/_search
    {
      "query": {
        "term": {
          "{FIELD}": "{VALUE}"
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • {FIELD} - 就是我们需要匹配的字段名
    • {VALUE} - 就是我们需要匹配的内容,除了TEXT类型字段以外的任意类型。

    2.3实现SQL的in语句-terms

    如果我们要实现SQL中的in语句,一个字段包含给定数组中的任意一个值就匹配。

    GET /order_v2/_search
    {
      "query": {
        "terms": {
          "{FIELD}": [
            "{VALUE1}",
            "{VALUE2}"
          ]
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • {FIELD} - 就是我们需要匹配的字段名
    • {VALUE1}, {VALUE2} … {VALUE N} - 就是我们需要匹配的内容,除了TEXT类型字段以外的任意类型。

    2.4范围查询

    通过range实现范围查询,类似SQL语句中的>, >=, <, <=表达式。

    GET /{索引名}/_search
    {
      "query": {
        "range": {
          "{FIELD}": {
            "gte": 10, 
            "lte": 20
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • {FIELD} - 字段名
    • gte范围参数 - 等价于>=
    • lte范围参数 - 等价于 <=
    • 范围参数可以只写一个,例如:仅保留 “gte”: 10, 则代表 FIELD字段 >= 10

    范围参数如下:

    • gt - 大于 ( > )
    • gte - 大于且等于 ( >= )
    • lt - 小于 ( < )
    • lte - 小于且等于 ( <= )

    2.5bool组合查询

    2.5.1bool查询基本语法结构

    在ES中bool查询就是用来组合布尔查询条件,布尔查询条件,就是类似SQL中的and (且)、or (或)

    前面的例子都是设置单个字段的查询条件,如果需要编写类似SQL的Where语句,组合多个字段的查询条件,可以使用bool语句。

    GET /{索引名}/_search
    {
      "query": {
        "bool": { // bool查询
          "must": [], // must条件,类似SQL中的and, 代表必须匹配条件
          "must_not": [], // must_not条件,跟must相反,必须不匹配条件
          "should": [] // should条件,类似SQL中or, 代表匹配其中一个条件
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    可以任意选择must、must_not和should条件的参数都是一个数组,意味着他们都支持设置多个条件

    2.5.2must条件

    类似SQL的and,代表必须匹配的条件。

    GET /{索引名}/_search
    {
      "query": {
        "bool": {
          "must": [
             {匹配条件1},
             {匹配条件2},
             ...可以有N个匹配条件...
            ]
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    2.5.3must_not条件

    跟must的作用相反。

    GET /{索引名}/_search
    {
      "query": {
        "bool": {
          "must_not": [
             {匹配条件1},
             {匹配条件2},
             ...可以有N个匹配条件...
            ]
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    2.5.4should条件

    类似SQL中的 or, 只要匹配其中一个条件即可

    GET /{索引名}/_search
     {
       "query": {
         "bool": {
           "should": [
              {匹配条件1},
              {匹配条件2},
              …可以有N个匹配条件…
             ]
         }
       }
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3.全文搜索

    3.1默认全文搜索

    默认情况下,使用全文搜索很简单,只要将字段类型定义为text类型,然后用match语句匹配即可

    ES对于text类型的字段,在插入数据的时候,会进行分词处理,然后根据分词的结果索引文档,当我们搜索text类型字段的时候,也会先对搜索关键词进行分词处理、然后根据分词的结果去搜索。

    ES默认的分词器是standard,对英文比较友好,例如:hello world 会被分解成 hello和world两个关键词,如果是中文会分解成一个一个字,例如:上海大学 会分解成: 上、海、大、学。

    3.2中文分词器

    ES默认的analyzer(分词器),对英文单词比较友好,对中文分词效果不好。不过ES支持安装分词插件,增加新的分词器。

    默认的分词器不满足需要,可以在定义索引映射的时候,指定text字段的分词器(analyzer)。

    PUT /article
    {
      "mappings": {
        "properties": {
          "title":   { 
              "type": "text",
              "analyzer": "smartcn"
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    只要在定义text字段的时候,增加一个analyzer配置,指定分词器即可,这里指定的分词器是smartcn。

    smartcn分词器:smartcn是目前ES官方推荐的中文分词插件,不过目前不支持自定义词库。

    ik分词器:ik支持自定义扩展词库,有时候分词的结果不满足我们业务需要,需要根据业务设置专门的词库,词库的作用就是自定义一批关键词,分词的时候优先根据词库设置的关键词分割内容,例如:词库中包含 “上海大学” 关键词,如果对“上海大学在哪里?”进行分词,“上海大学” 会做为一个整体被切割出来。

    4. 排序

    ES的默认排序是根据相关性分数排序,如果我们想根据查询结果中的指定字段排序,需要使用sort Processors处理。

    GET /{索引名}/_search
    {
      "query": {
        ...查询条件....
      },
      "sort": [
        {
          "{Field1}": { // 排序字段1
            "order": "desc" // 排序方向,asc或者desc, 升序和降序
          }
        },
        {
          "{Field2}": { // 排序字段2
            "order": "desc" // 排序方向,asc或者desc, 升序和降序
          }
        }
        ....多个排序字段.....
      ]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    sort子句支持多个字段排序,类似SQL的order by。

    三、聚合分析

    ES中的聚合查询,类似SQL的sum/avg/count/GROUP BY分组查询,主要用于统计分析场景。一般统计分析主要分为两个步骤:分组

    、组内聚合

    核心概念

    • :满足特定条件的文档的集合。桶的就是一组数据的集合,对数据分组后,得到一组组的数据,就是一个个的桶。

      提示:桶等同于组,分桶和分组是一个意思,ES使用桶代表一组相同特征的数据。

    • 指标:对文档进行统计计算方式,又叫指标聚合。桶内聚合,说的就是先对数据进行分组(分桶),然后对每一个桶内的数据进行指标聚合。说白了就是,前面将数据经过一轮桶聚合,把数据分成一个个的桶之后,我们根据上面计算指标对桶内的数据进行统计。

      常用的指标有:SUM、COUNT、MAX等统计函数。

    1.指标聚合

    ES指标聚合,就是类似SQL的统计函数,指标聚合可以单独使用,也可以跟桶聚合一起使用。

    1.1 value_count 值聚合

    主要用于统计文档总数,类似SQL的count函数。

    GET /sales/_search?size=0
    {
      "aggs": {
        "types_count": { // 聚合查询的名字,随便取个名字
          "value_count": { // 聚合类型为:value_count
            "field": "type" // 计算type这个字段值的总数
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    等价SQL:

    select count(type) from sales
    
    • 1

    返回结果:

    {
        ...
        "aggregations": {
            "types_count": { // 聚合查询的名字
                "value": 7 // 统计结果
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    1.2 cardinality 基数聚合

    基数聚合,也是用于统计文档的总数,跟Value Count的区别是,基数聚合会去重,不会统计重复的值,类似SQL的count(DISTINCT 字段)用法。

    POST /sales/_search?size=0
    {
        "aggs" : {
            "type_count" : { // 聚合查询的名字,随便取一个
                "cardinality" : { // 聚合查询类型为:cardinality
                    "field" : "type" // 根据type这个字段统计文档总数
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    等价SQL:

    select count(DISTINCT type) from sales
    
    • 1

    返回结果:

    {
        ...
        "aggregations" : {
            "type_count" : { // 聚合查询的名字
                "value" : 3 // 统计结果
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    1.3avg/sum/max/min

    • avg - 求平均值

    • sum - 求和

    • max - 求最大值

    • min - 求最小值

    这些函数的使用形式和结果形式都和上面是类似的,仅需替换函数就好。

    2.分组统计

    数据分组在es中叫做桶聚合。桶聚合一般不单独使用,都是配合指标聚合一起使用,对数据分组之后肯定要统计桶内数据,在ES中如果没有明确指定指标聚合,默认使用value_count指标聚合,统计桶内文档总数。

    2.1Terms聚合(唯一值分组)

    terms聚合的作用跟SQL中group by作用一样,都是根据字段唯一值对数据进行分组(分桶),字段值相等的文档都分到同一个桶内。

    GET /order/_search?size=0
    {
      "aggs": {
        "shop": { // 聚合查询的名字,随便取个名字
          "terms": { // 聚合类型为: terms
            "field": "shop_id" // 根据shop_id字段值,分桶
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    等价SQL:

    select shop_id, count(*) from order group by shop_id
    
    • 1

    返回结果:

    {
        ...
        "aggregations" : {
            "shop" : { // 聚合查询名字
                "buckets" : [ // 桶聚合结果,下面返回各个桶的聚合结果
                    {
                        "key" : "1", // key分桶的标识,在terms聚合中,代表的就是分桶的字段值
                        "doc_count" : 6 // 默认的指标聚合是统计桶内文档总数
                    },
                    {
                        "key" : "5",
                        "doc_count" : 3
                    },
                    {
                        "key" : "9",
                        "doc_count" : 2
                    }
                ]
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    2.2Histogram聚合(数值间隔分组)

    histogram(直方图)聚合,主要根据数值间隔分组,使用histogram聚合分桶统计结果,通常用在绘制条形图报表。

    POST /sales/_search?size=0
    {
        "aggs" : {
            "prices" : { // 聚合查询名字,随便取一个
                "histogram" : { // 聚合类型为:histogram
                    "field" : "price", // 根据price字段分桶
                    "interval" : 50 // 分桶的间隔为50,意思就是price字段值按50间隔分组
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    返回结果:

    {
        ...
        "aggregations": {
            "prices" : { // 聚合查询名字
                "buckets": [ // 分桶结果
                    {
                        "key": 0.0, // 桶的标识,histogram分桶,这里通常是分组的间隔值
                        "doc_count": 1 // 默认按Value Count指标聚合,统计桶内文档总数
                    },
                    { 
                        "key": 50.0,
                        "doc_count": 1
                    },
                    {
                        "key": 100.0,
                        "doc_count": 0
                    },
                    {
                        "key": 150.0,
                        "doc_count": 2
                    }
                ]
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    2.3date_histogram聚合(时间间隔分组)

    类似histogram聚合,区别是Date histogram可以很好的处理时间类型字段,主要用于根据时间、日期分桶的场景。

    POST /sales/_search?size=0
    {
        "aggs" : {
            "sales_over_time" : { // 聚合查询名字,随便取一个
                "date_histogram" : { // 聚合类型为: date_histogram
                    "field" : "date", // 根据date字段分组
                    "calendar_interval" : "month", // 分组间隔:month代表每月、支持minute(每分钟)、hour(每小时)、day(每天)、week(每周)、year(每年)
                    "format" : "yyyy-MM-dd" // 设置返回结果中桶key的时间格式
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    返回结果:

    {
        ...
        "aggregations": {
            "sales_over_time": { // 聚合查询名字
                "buckets": [ // 桶聚合结果
                    {
                        "key_as_string": "2015-01-01", // 每个桶key的字符串标识,格式由format指定
                        "key": 1420070400000, // key的具体字段值
                        "doc_count": 3 // 默认按Value Count指标聚合,统计桶内文档总数
                    },
                    {
                        "key_as_string": "2015-02-01",
                        "key": 1422748800000,
                        "doc_count": 2
                    },
                    {
                        "key_as_string": "2015-03-01",
                        "key": 1425168000000,
                        "doc_count": 2
                    }
                ]
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    2.4Range聚合(数值范围分组)

    range聚合,按数值范围分桶。

    GET /_search
    {
        "aggs" : {
            "price_ranges" : { // 聚合查询名字,随便取一个
                "range" : { // 聚合类型为: range
                    "field" : "price", // 根据price字段分桶
                    "ranges" : [ // 范围配置
                        { "to" : 100.0 }, // 意思就是 price <= 100的文档归类到一个桶
                        { "from" : 100.0, "to" : 200.0 }, // price>100 and price<200的文档归类到一个桶
                        { "from" : 200.0 } // price>200的文档归类到一个桶
                    ]
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    返回结果:

    {
        ...
        "aggregations": {
            "price_ranges" : { // 聚合查询名字
                "buckets": [ // 桶聚合结果
                    {
                        "key": "*-100.0", // key可以表达分桶的范围
                        "to": 100.0, // 结束值
                        "doc_count": 2 // 默认按Value Count指标聚合,统计桶内文档总数
                    },
                    {
                        "key": "100.0-200.0",
                        "from": 100.0, // 起始值
                        "to": 200.0, // 结束值
                        "doc_count": 2
                    },
                    {
                        "key": "200.0-*",
                        "from": 200.0,
                        "doc_count": 3
                    }
                ]
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    大家仔细观察的话,发现range分桶,默认key的值不太友好,尤其开发的时候,不知道key长什么样子,处理起来比较麻烦,我们可以为每一个分桶指定一个有意义的名字。

    GET /_search
    {
        "aggs" : {
            "price_ranges" : {
                "range" : {
                    "field" : "price",
                    "keyed" : true,
                    "ranges" : [
                        // 通过key参数,配置每一个分桶的名字
                        { "key" : "cheap", "to" : 100 },
                        { "key" : "average", "from" : 100, "to" : 200 },
                        { "key" : "expensive", "from" : 200 }
                    ]
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2.5综合例子

    前面的例子,都是单独使用aggs聚合语句,代表直接统计所有的文档,实际应用中,经常需要配合query语句,先搜索目标文档,然后使用aggs聚合语句对搜索结果进行统计分析。聚合查询支持多层嵌套

    GET /cars/_search
    {
        "size": 0, // size=0代表不需要返回query查询结果,仅仅返回aggs统计结果
        "query" : { // 设置查询语句,先赛选文档
            "match" : {
                "make" : "ford"
            }
        },
        "aggs" : { // 然后对query搜索的结果,进行统计
            "colors" : { // 聚合查询名字
                "terms" : { // 聚合类型为:terms 先分桶
                  "field" : "color"
                },
                "aggs": { // 通过嵌套聚合查询,设置桶内指标聚合条件
                  "avg_price": { // 聚合查询名字
                    "avg": { // 聚合类型为: avg指标聚合
                      "field": "price" // 根据price字段计算平均值
                    }
                  },
                  "sum_price": { // 聚合查询名字
                    "sum": { // 聚合类型为: sum指标聚合
                      "field": "price" // 根据price字段求和
                    }
                  }
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    3.多桶排序

    类似terms、histogram、date_histogram这类桶聚合都会动态生成多个桶,如果生成的桶特别多,我们如何确定这些桶的排序顺序,如何限制返回桶的数量。默认情况,ES会根据doc_count文档总数,降序排序。ES桶聚合支持两种方式排序:内置排序按度量指标排序

    3.1多桶排序

    3.1.1内置排序
    • _count - 按文档数排序。对 terms 、 histogram 、 date_histogram 有效
    • _term - 按词项的字符串值的字母顺序排序。只在 terms 内使用
    • _key - 按每个桶的键值数值排序, 仅对 histogram 和 date_histogram 有效
    GET /cars/_search
    {
        "size" : 0,
        "aggs" : {
            "colors" : { // 聚合查询名字,随便取一个
                "terms" : { // 聚合类型为: terms
                  "field" : "color", 
                  "order": { // 设置排序参数
                    "_count" : "asc"  // 根据_count排序,asc升序,desc降序
                  }
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    3.1.2按度量排序

    通常情况下,我们根据桶聚合分桶后,都会对桶内进行多个维度的指标聚合,所以我们也可以根据桶内指标聚合的结果进行排序。

    GET /cars/_search
    {
        "size" : 0,
        "aggs" : {
            "colors" : { // 聚合查询名字
                "terms" : { // 聚合类型: terms,先分桶
                  "field" : "color", // 分桶字段为color
                  "order": { // 设置排序参数
                    "avg_price" : "asc"  // 根据avg_price指标聚合结果,升序排序。
                  }
                },
                "aggs": { // 嵌套聚合查询,设置桶内聚合指标
                    "avg_price": { // 聚合查询名字,前面排序引用的就是这个名字
                        "avg": {"field": "price"} // 计算price字段平均值
                    }
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    3.2限制返回桶的数量

    如果分桶的数量太多,可以通过给桶聚合增加一个size参数限制返回桶的数量。

    GET /_search
    {
        "aggs" : {
            "products" : { // 聚合查询名字
                "terms" : { // 聚合类型为: terms
                    "field" : "product", // 根据product字段分桶
                    "size" : 5 // 限制最多返回5个桶
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    四、Java快速接入ES

    这里使用的es的版本为7.x

    1.依赖与配置

    <dependency>
      <groupId>org.springframework.bootgroupId>
      <artifactId>spring-boot-starter-data-elasticsearchartifactId>
      <version>2.4.2version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pwMiuPOF-1663066410029)(%E8%BD%AF%E4%BB%B6%E7%B3%BB%E7%BB%9F-7.ES.assets/image-20220902144006346.png)]

    es的版本差异不同,其结构发生很多变化,这里仅以其中一个版本介绍。

    spring:
      elasticsearch:
        rest:
          uris: 127.0.0.1:9200
    
    • 1
    • 2
    • 3
    • 4

    2.使用

    Elasticsearch从6.x升级到7.x改动还真不是一般的大,ElasticsearchTemplate不建议使用了,改为使用ElasticsearchRestTemplate,ElasticsearchRepository实现复杂查询的方法也不建议使用了。从此我们简单的数据操作可以使用ElasticsearchRepository,而复杂的数据操作只能使用ElasticsearchRestTemplate了。

    public interface EsRepository extends ElasticsearchRepository<UserDocument, Long> {
    }
    
    • 1
    • 2

    五、Java整合ES的注意

    1.@Document

    一般使用@Document(indexName = "technical_es_test", useServerConfiguration = true, createIndex = false)

    @Persistent
    @Inherited
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE})
    public @interface Document {
        //索引库名称
        String indexName();
        //类型
        String type() default "";
        //
        boolean useServerConfiguration() default false;
        //默认分片数5
        short shards() default 5;
        //默认副本数1
        short replicas() default 1;
        //刷新间隔
        String refreshInterval() default "1s";
        //索引文件存储类型
        String indexStoreType() default "fs";
       //是否创建索引
        boolean createIndex() default true;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    2.@Field 与 枚举类FieldType

    作用于document文档的实体类

    @Id:作用在成员变量,标记一个字段为id主键;一般id字段或是域不需要存储也不需要分词;

    @Field作用在成员变量,标记为文档的字段,并制定映射属性;一般使用@Field(type = FieldType.Long, store = true)

    @Field

    (1)type:字段的类型,取值是枚举,FieldType;

    (2)index:是否索引,布尔值类型,默认是true;

    (3)store:是否存储,布尔值类型,默认值是false;

    (4)analyzer:分词器名称

    FieldType

    public enum FieldType {
      Text,
      Integer,
      Long,
      Date,
      Float,
      Double,
      Boolean,
      Object,
      Auto,
      Nested,
      Ip,
      Attachment,
      Keyword;
    
      private FieldType() {
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    【 @Field(type = FieldType.Keyword)和 @Field(type = FieldType.Text)区别】

      在早期elasticsearch5.x之前的版本存储字符串只有string字段;但是在elasticsearch5.x之后的版本存储了KeywordText,都是存储字符串的。FieldType.Keyword存储字符串数据时,不会建立索引;而FieldType.Text在存储字符串数据的时候,会自动建立索引,也会占用部分空间资源。
    
    • 1

    3.布尔查询 BoolQueryBuilder

    BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();

    • must子句:文档必须匹配must查询条件;
    • should子句:文档应该匹配should子句查询的一个或多个;
    • must_not子句:文档不能匹配该查询条件;
    • filter子句:过滤器,文档必须匹配该过滤条件,跟must子句的唯一区别是,filter不影响查询的score;

    filter子句中可以再传入一个BoolQueryBuilder,通过QueryBuilders的下列方式进行匹配。

    termQuery("key", obj); 						 //完全匹配
    termsQuery("key", obj1, obj2..);   //一次匹配多个值
    matchQuery("key", Obj);		 				 //单个匹配, field不支持通配符, 前缀具高级特性
    multiMatchQuery("text", "field1", "field2"..);  //匹配多个字段, field有通配符忒行
    matchAllQuery();         					 //匹配所有文件
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在布尔查询中:

    各个子句之间的逻辑关系是与(and)。对于单个子句,只要一个文档满足该子句的查询条件,返回的逻辑结果就是true。

    对于should子句,它一般包含多个子查询条件,参数 minimum_should_match 控制文档必须满足should子句中的子查询条件的数量,只有当文档满足指定数量的should查询条件时,should子句返回的逻辑结果才是true。

    参考:https://www.cnblogs.com/ljhdo/p/5040252.html

  • 相关阅读:
    Python继承和组合 工厂模式、单例模式实现如下需求
    【Leetcode刷题Python】516. 最长回文子序列
    javeEE高校专业实训评价系统ssm
    windows jdk 11.0.21版本安装配置
    玩玩“小藤”开发者套件 Atlas 200I DK A2 之部署智能语音助手
    dotnet 6 使用 string.Create 提升字符串创建和拼接性能
    CF1490F Equalize the Array
    Unity Shader Graph 节点入门
    侯捷 - C++ Startup 揭密:C++ 程序的生前和死后 (四)
    如何设计缓存中间层
  • 原文地址:https://blog.csdn.net/qq_44625080/article/details/126839346