• 【中间件】ElasticSearch:ES的基本概念与基本使用


    ElasticSearch

    ElasticSearch基本概念

    Index索引、Type类型,类似于数据库中的数据库和表,我们说,ES的数据存储在某个索引的某个类型中(某个数据库的某个表中),Document文档(JSON格式),相当于是数据库中内容的存储方式

    MySQL:数据库、表、数据

    ElasticSearch:索引、类型、文档

    概念:倒排索引

    ElasticSearch的检索功能基于其倒排索引机制,该机制允许对检索的关键词进行拆分并判断其相关性得分,根据相关性得分再取得检索的结果排序,根据该排序返回具体的结果

    ElasticSearch的安装

    Docker安装ElasticSearch以及其可视化界面Kibana

    拉取ES和Kibana,注意一定要注意ES的版本问题,不能直接拉取latest版本

    进行ES的进一步安装,包括挂载等操作:

    创建两个文件夹:mydata/elasticsearch/config 和 mydata/elasticsearch/data 用来挂载ES的配置和数据

    进行一个写入操作:

    echo "http.host: 0.0.0.0" >> /mydata/elasticsearch/config/elasticsearch.yml
    
    • 1

    创建并挂载ElasticSearch:

    docker run --name elasticsearch -p 9200:9200 -p 9300:9300 \
    -e "discovery.type=single-node" \
    -e ES_JAVA_OPTS="-Xms64m -Xmx512m" \
    -v /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
    -v /mydata/elasticsearch/data:/usr/share/elasticsearch/data \
    -v /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins \
    -d elasticsearch:7.4.2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    docker run --name elasticsearch -p 9200:9200 -p 9300:9300 \
    -e "discovery.type=single-node" \
    -e ES_JAVA_OPTS="-Xms64m -Xms128m" \
    -v /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
    -v /mydata/elasticsearch/data:/usr/share/elasticsearch/data \
    -v /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins \
    -d elasticsearch:latest
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • run --name 是为容器起名并使其暴露两个端口,端口1是发送请求的端口,端口2是集群的通信端口

    • -e “discovery.type=single-node” \ 是令其以单节点方式启动

    • -e ES_JAVA_OPTS=“-Xms64m -Xms128m” \ 设置允许其占用的内存大小,64-128M,在实际上线中,其大概分配32G以上

    • 后面的就是挂载和指定镜像

    Docker安装ES的一些细节

    注意在Docker安装ES时,可能会出现权限不足导致ES已启动就立刻自动关闭的情况,这时就需要我们修改挂载在外部系统的文件夹的权限:

    执行:

    chmod -R 777 /mydata/elasticsearch
    
    • 1

    之后在浏览器中发送:网址:9200就可以判断ES是否安装成功

    安装ES的可视化界面KIBANA

    PULL拉取kibana之后执行下面操作:

     docker run --name kibana -e ELASTICSEARCH_HOSTS=http://8.141.85.98:9200 -p 5601:5601 \
     -d kibana:7.4.2
    
    • 1
    • 2
    • -e 指定的是对应的ES的地址,
    • -p 是指kibana暴露出的端口号
    • -d 指的是使用哪个镜像进行容器的创建

    注意就算这里没有指定,我们也可以在kibana的配置文件中进行指定

    ElasticSearch基本使用

    ES的所有使用方式都以RestFul API的方式被封装为请求了,我们可以通过浏览器发送请求的方式来实现ES的使用

    一些小功能

    GET /_cat/nodes			查看节点
    GET /_cat/health		查看节点健康状况
    GET /_cat/master		查看主节点
    GET /_cat/indices		查看所有索引
    
    • 1
    • 2
    • 3
    • 4

    尝试:新增、修改数据

    在customer索引下的external类型中保存1号数据的内容为:

    {
        "name":"Jhon Doe"
    }
    
    • 1
    • 2
    • 3

    注意一定要是PUT操作:

    http://8.141.85.98:9200/customer/external/1
    
    • 1

    在发送的JSON中写入内容,注意新增和更新都是PUT操作,第一次是新增,后续再操作就是更新

    但注意,如果我们在发送请求时不指定id,ES会为我们自动生成一个随机id,而我们的操作每次都是新增操作

    注意PUT和POST有相同的效果,但PUT要求必须指定ID,POST在不指定ID的情况下会随机生成

    查询数据

    查询数据要发送get请求,举例查询:

    返回的内容:

    {
        "_index": "customer",
        "_type": "external",
        "_id": "1",
        "_version": 1,
        "_seq_no": 0,
        "_primary_term": 1,
        "found": true,
        "_source": {
            "name": "Jhon Doe"
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    此处要注意的是"_seq_no"字段,该字段是并发控制字段,使用乐观锁的方式进行并发控制:

    我们可以在发送请求时携带并发判断字段:若版本未被其他业务修改,才进行修改,若已被其他业务修改,则自己不做任何操作:

    POST:

    http://8.141.85.98:9200/customer/external/1?if_seq_no=0&if_primary_term=1
    
    • 1

    若两个if后携带的字段都匹配的话,才会进行修改操作,这样规避了并发操作场景下结果的不可预测性

    更新的几种操作

    • POST带_update:

      http://8.141.85.98:9200/customer/external/1/_update
      
      • 1

      这种操作会对比原先的数据,若一致则什么也不做(版本号,并发控制字段都不改变),若不一致才进行修改,但注意我们带_update的修改要在修改的内容前加doc

      {
      	"doc":{
      		"name":"Jhon Doe"
      	}
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5

      对于其他的更新操作都不会进行数据对比,直接进行更新覆盖,并修改版本号和并发编程字段

    删除

    以DELETE的方式发送和查询一样的请求就可以做到删除了

    ES复杂查询

    Bulk批量操作API

    使用对应的操作进行批量的增删改操作:

    发送POST请求:

    http://192.168.0.1:9200/customer/external/_bulk
    
    • 1

    索引、类型、_bulk进行批量操作,这些批量操作的方式是:

    每一次修改都是两个JSON数据,第一条是元数据,用来指定操作的具体数据以及操作的方式

    POST /customer/external/_bulk
    {"index":{"_id":1}}
    {"name":"Jhon Doe"}
    {"index":{"_id":2}}
    {"name":"Tom Jackson"}
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在Kibana中进行测试:

    {
      "took" : 10,					// 花费的时间:10ms
      "errors" : false,				// 未发生错误
      "items" : [
        {
          "index" : {
            "_index" : "customer",			// 操作的索引
            "_type" : "external",			// 操作的类型
            "_id" : "1",					// 操作的数据项id
            "_version" : 3,					// 版本
            "result" : "updated",			// 操作属性
            "_shards" : {
              "total" : 2,
              "successful" : 1,
              "failed" : 0
            },
            "_seq_no" : 2,					// 并发控制版本号
            "_primary_term" : 1,
            "status" : 200					// 200代表修改、201代表新建
          }
        },
        {
          "index" : {
            "_index" : "customer",
            "_type" : "external",
            "_id" : "2",
            "_version" : 1,
            "result" : "created",
            "_shards" : {
              "total" : 2,
              "successful" : 1,
              "failed" : 0
            },
            "_seq_no" : 3,
            "_primary_term" : 1,
            "status" : 201
          }
        }
      ]
    }
    
    • 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
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    复杂的批量操作

    不在发送请求时指定索引和类型,在文档信息中进行具体的指定

    POST _bulk
    {"delete":{"_index":"website", "_type":"blog", "_id":"123"}}
    {"create":{"_index":"website", "_type":"blog", "_id":"123"}}
    {"title": "My first blog"}
    {"index":{"_index":"website", "_type":"blog"}}
    {"title": "My second blog"}
    {"update":{"_index":"website", "_type":"blog", "_id":"123"}}
    {"doc": {"title": "My updated Blog"}}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    导入测试数据进行测试:(省略)

    发送如下请求查看ES中数据的整体信息:

    http://8.141.85.98:9200/_cat/indices
    
    • 1

    复杂查询

    查询:查询所有数据的所有信息,并按照账户id排序:

    GET bank/_search?q=*&sort=account_number:asc
    
    • 1

    查询出的结果:

    {
      "took" : 30,					
      "timed_out" : false,
      "_shards" : {						// shards中存放的是分布式存储过程中的各个结点的操作信息
        "total" : 1,
        "successful" : 1,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : {
          "value" : 1000,
          "relation" : "eq"
        },
        "max_score" : null,				// 查询操作匹配的最大得分
        "hits":[]						// 具体内容
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    QueryDSL(ES专属查询语言)

    基本操作

    ES所提供的查询操作:请求发送之后,紧接着发送一个JSON格式的查询语言,用来规定查询条件:

    GET bank/_search
    {
        "query":{
            "match_all":{}				// 不设置匹配条件,查询所有信息
        },
        "sort": [
            {
                "balance": {
                    "order": "desc"			// 以账户余额降序排序
                }
            }
        ],
        "from": 5,				// 从第五条数据开始
        "size": 6,				// 展示6条数据
        "_source": ["balance", "firstname"]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    设置查询条件的情况:

    若我们的查询条件不为字符串,则代表我们所做的是精确查询,若为字符串,则是模糊查询:

    精确查询
    GET bank/_search
    {
      "query": {
        "match":{
          "balance": 16418
        } 
      }
    }
    
    模糊查询
    GET bank/_search
    {
      "query": {
        "match":{
          "address": "Kings"
        } 
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    ES全文检索会对分词进行匹配,对每一个分词都在全文中进行检索,并以得分从高到低进行数据的返回

    使用match_phrase进行不分词的整体匹配,这样就会和MySql中的模糊查询一样进行整体匹配了:

    GET bank/_search
    {
      "query": {
        "match_phrase":{
          "address": "mill road"
        } 
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    多字段查询

    使用multi_match进行多字段的查询:

    GET bank/_search
    {
      "query": {
        "multi_match": {
          "query": "mill movico",
          "fields": ["address", "city"]
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    对于每个字段,都进行查询,并且会进行分词查询

    多字段拼接查询条件

    使用bool进行查询条件的拼接:

    GET bank/_search
    {
      "query": {
        "bool": {
          "must": [
            {"match": {
              "gender": "M"
            }},
            {"match": {
              "address": "mill"
            }}
          ],
          "must_not": [
            {"match": {
              "age": 18
            }}
          ],
          "should": [
            {
              "match": {
                "lastname": "Wallace"
              }
            }  
          ]
        }
      }
    }
    
    • 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
    • must:必须匹配
    • must_not:必须不匹配
    • should:最好满足(应该)若满足会增加权重

    区间:

    "filter": {
        "range": {
            "age": {
                "gte": 18, 
                "lte": 30
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    注意filter会只进行过滤,不会增加得分,而must、must_not、should都会增加相关性得分

    • term:term只适用于精确查询,尤其适合对于非文本类型的检索,注意对于文档类型的查询,一定不要使用term

    • match_phrase:模糊查询

    • "match": {
      	"address.keyword": "xxxxxx"
      }
      
      • 1
      • 2
      • 3

      这个是精确查询

    总结:对于非文本字段,都以term进行查询,对于文本字段,都以match进行查询

    ES的数据分析功能(聚合)

    示例

    ## 搜索address中包含mill的所有人的年龄分布(取出每个年龄的人有几个(term)并显示10条记录)以及平均年龄
    GET bank/_search
    {
      "query":{
        "match": {
          "address": "mill"
        }
      },
      "aggs": {
        "ageAgg": {
          "terms": {
            "field": "age", 
            "size": 10
          }
        },
        "avgAgg": {
          "avg": {
            "field": "age"
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    注意:在以文本字段为组进行分组时,我们必须在字段后添加.keyword

    ## 按照年龄聚合,并求这些年龄段人的平均薪资,并按照年龄分布对同一性别的人进行聚合,查他们的平均薪资
    GET bank/_search
    {
      "query": {
        "match_all": {}
      }, 
      "aggs": {
        "ageAgg": {
          "terms": {
            "field": "age", 
            "size": 100
          },
          "aggs": {
            "genderAgg": {
              "terms": {
                "field": "gender.keyword"
              },
              "aggs": {
                "balanceAgg": {
                  "avg": {
                    "field": "balance"
                  }
                }
              }
            }
          }
        }
      }
    }
    
    • 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
    • 29

    映射

    我们在向ES中存储数据时,ES会自动猜测我们的数据类型,如果是纯数字会被映射为Long类型,其他会被映射为text类型,而这种映射有时候不是我们想要的,我们在创建的时候就可以提前指定映射类型。

    PUT /my_index
    {
      "mappings": {
        "properties": {
          "age": {"type": "integer"},
          "email": {"type": "keyword"}, 
          "name": {"type": "text"}
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    映射类型不为text的都不会被分词器进行检索,keyword只会被精确检索

    添加一个属性只能新增:

    PUT my_index/_mapping
    {
      "properties": {
        "employee-id": {
          "type": "keyword", 
          "index": false
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    通过下面请求来查看映射信息:

    GET my_index/_mapping
    
    • 1

    映射的修改

    映射是不可以进行直接修改的,我们必须进行数据迁移才能完成对ES中映射关系的修改:

    新增一个对应的索引

    PUT newbank
    {
      "mappings": {
        "properties": {
            "account_number" : {
              "type" : "long"
            },
            "address" : {
              "type" : "text"
            },
            "age" : {
              "type" : "integer"
            },
            "balance" : {
              "type" : "long"
            },
            "city" : {
              "type" : "keyword"
            },
            "email" : {
              "type" : "keyword"
            },
            "employer" : {
              "type" : "keyword"
            },
            "firstname" : {
              "type" : "text"
            },
            "gender" : {
              "type" : "keyword"
            },
            "lastname" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            },
            "state" : {
              "type" : "keyword"
            }
        }
      }
    }
    
    • 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
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    将老索引的配置迁移给新索引:

    POST _reindex
    {
      "source": {
        "index": "bank", 
        "type": "account"
      },
      "dest": {
        "index": "newbank"
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    分词

    ES将一句话分成若干个词,并按照分成的词进行全文检索,返回一个相关性排序的结果。

    分词器

    标准分词器尝试(中文):

    POST _analyze
    {
      "analyzer": "standard", 
      "text": "分词器测试"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    分词结果为:‘分’、‘词’、‘器’、‘测’、‘试’

    其实很不符合中文语境

    ik分词器

    ik分词器是一个基于中文语境的ES分词器,我们在github上找到他并对应ES版本进行安装(7.4.2)

    使用如下命令安装ik分词器对应的7.4.2版本

    wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.4.2/elasticsearch-analysis-ik-7.4.2.zip

    这样很简便,但非常慢,我们也可以直接下载下来再上传完成这个操作

    之后解压就算安装好了ik分词器,我们进入容器的bin目录执行:elasticsearch-list命令来查看分词器是否安装完成

    之后我们就可以使用,ik分词器最常用的两种分词方式:

    ## 智能分词方式,
    POST _analyze
    {
      "analyzer": "ik_smart", 
      "text": "我是中国人"
    }
    我、是、中国人
    
    ## 最大分词方式
    POST _analyze
    {
      "analyzer": "ik_max_word", 
      "text": "我是中国人"
    }
    我、是、中国人、中国、国人
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    但是,ik分词器虽然能够对中文分词有较为合理的分词基础,但对于一些比较具有时效性的分词,其还是不能进行很智能的分词,故我们还要进行词库拓展:

    删除原先的ES容器,并重新安装,给它赋予更大的内存,但注意,ES不会丢失数据,因为数据已经进行过挂载(这里其实不用):

    docker run --name elasticsearch -p 9200:9200 -p 9300:9300 \
    -e "discovery.type=single-node" \
    -e ES_JAVA_OPTS="-Xms64m -Xmx512m" \
    -v /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
    -v /mydata/elasticsearch/data:/usr/share/elasticsearch/data \
    -v /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins \
    -d elasticsearch:7.4.2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在Linux的mydata文件夹下创建一个文件夹:nginx用来存放nginx的相关配置信息:

    直接创建一个nginx容器用来复制器配置信息(不需要拉取镜像,如果没有镜像会自动拉取):

    docker run -p 80:80 --name nginx -d nginx:1.10
    
    • 1

    复制这个nginx的配置文件到我们新建的nginx文件夹中:

    docker container cp nginx:/etc/nginx .
    
    • 1

    移除刚刚创建的nginx容器,将刚刚的文件夹重命名为conf,再将这个文件夹移动到新建一个nginx中

     docker run -p 80:80 --name nginx \
     -v /mydata/nginx/html:/usr/share/nginx/html \ 
     -v /mydata/nginx/logs:/var/log/nginx \
     -v /mydata/nginx/conf:/etc/nginx \
     -d nginx:1.10
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这样nginx就创建好了,我们可以在html文件中创建一个index.html来显示首页

    我们在html文件夹中创建一个es文件夹,用来存放定制化分词信息

    创建一个fenci.txt的文件,存放以下内容(分词内容):

    清河
    南开
    中移
    
    • 1
    • 2
    • 3

    在es的挂载的plugins文件夹中的conf文件夹中的IKAnalyzer.cfg.xml文件夹中进行修改:

    更改远程那部分为自己的远程部分:http://xxxxxxxxxxxxxx/es/fenci.txt就可以了

    SpringBoot整合ES

    • JestClient: 非官方、更新慢
    • RestTemplate、HttpClient等模拟HTTP请求发送的组件:模拟HTTP请求的发送,很多ES操作需要自己封装,操作较为繁琐
    • 使用elasticsearch-rest-high-level-client依赖,这个依赖提供了便捷丰富的ES功能,这里也使用这种方式进行整合

    在Java项目中建立一个新的包用来管理ES搜索服务

    注意:只添加Web依赖,我选用SpringBoot 2.7.15版本

    导入ElasticSearch依赖:

    		<dependency>
    			<groupId>org.elasticsearch.clientgroupId>
    			<artifactId>elasticsearch-rest-high-level-clientartifactId>
    			<version>7.4.2version>
    		dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    同时注意:SpringBoot也集成了ES版本,这个版本很可能与我们自己选用的ES版本冲突,故我们必须对SpringBoot自动集成的ES版本进行修改:

    	<properties>
    		<java.version>1.8java.version>
    		<elasticsearch.version>7.4.2elasticsearch.version>
    	properties>
    
    • 1
    • 2
    • 3
    • 4

    在application.properties中配置注册中心:

    spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
    
    spring.application.name=gulimail-search
    
    • 1
    • 2
    • 3

    创建配置类:config/GulimailElasticSearchConfig

    @Configuration
    public class GulimailElasticSearchConfig {
    }
    
    • 1
    • 2
    • 3

    在启动类中添加启动注解:

    @EnableDiscoveryClient
    
    • 1

    在配置类中添加Bean

        @Bean
        public RestHighLevelClient esRestClient() {
            RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(new HttpHost("8.141.85.94", 9200, "http")));
            return client;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    之后测试一下:看看能不能注入

    	@Autowired
    	private RestHighLevelClient client;
    
    • 1
    • 2

    导入ES配置项信息

    想配置类中导入ES的配置项信息,搜索ElasticSearch High Level 找 RequestOptions

    这些配置项可以要求ES在被访问时必须携带某些信息才可以进行访问

        public static final RequestOptions COMMON_OPTIONS;
        static {
            RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
    //        builder.addHeader("Authorization", "Bearer " + TOKEN);
    //        builder.setHttpAsyncResponseConsumerFactory(
    //                new HttpAsyncResponseConsumerFactory
    //                        .HeapBufferedResponseConsumerFactory(30 * 1024 * 1024 * 1024));
            COMMON_OPTIONS = builder.build();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    简单测试

    	@Test
    	public void indexData() throws IOException {
    		IndexRequest indexRequest = new IndexRequest("users");		// 调用构造器时指定索引
    		indexRequest.id("1");										// 指定所添加字段的id
    		User user = new User();
    		user.setId(8L);
    		user.setName("虎开发");
    		user.setAge(20);
    		String userString = JSON.toJSONString(user);
    		indexRequest.source(userString, XContentType.JSON);					// 将要保存的内容存在对应的IndexRequest对象中
    		IndexResponse index = client.index(indexRequest, GulimailElasticSearchConfig.COMMON_OPTIONS);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    之后就可以在ES中查询到了

    复杂检索功能(使用ES提供的API)

    一个带有聚合的复杂检索示例

    /**
    	 * 创建检索请求
    	 */
    	@Test
    	public void searchData() throws IOException {
    		// 1. 创建检索请求
    		SearchRequest searchRequest = new SearchRequest();
    		searchRequest.indices("bank");			// 指定要搜索的索引
    		// 指定DSL检索条件
    		SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    		/**
    		 * sourceBuilder.query
    		 * sourceBuilder.from
    		 * sourceBuilder.size
    		 * sourceBuilder.aggregation
    		 *
    		 * sourceBuilder.query()里面也可以拼matchAll方法用来查全部
    		 */
    		sourceBuilder.query(QueryBuilders.matchQuery("address", "mill"));		// 匹配address字段中mill的值
    		searchRequest.source(sourceBuilder);			// 将查询条件传给searchRequest
    
    		// 聚合(构建聚合条件)
    		TermsAggregationBuilder terms = AggregationBuilders.terms("aggAgg").field("age").size(10);
    		sourceBuilder.aggregation(terms);		// 将聚合拼接到查询中
    
    		AvgAggregationBuilder balanceAgg = AggregationBuilders.avg("balanceAgg").field("balance");
    		sourceBuilder.aggregation(balanceAgg);
    
    
    		SearchResponse searchResponse = client.search(searchRequest, GulimailElasticSearchConfig.COMMON_OPTIONS);
    
    		SearchHits hits = searchResponse.getHits();// 获取大hits
    		SearchHit[] hitsObjects = hits.getHits();// 获取具体的数据
    		// 之后遍历就行,这里不遍历了
    
    		Aggregations aggregations = searchResponse.getAggregations();
    		Terms term = aggregations.get("aggAgg");		// 以Term方式的聚合可以直接转换为Term类型
    		for (Terms.Bucket bucket : term.getBuckets()) {
    			String keyAsString = bucket.getKeyAsString();
    			System.out.println("年龄:" + keyAsString + "==>" + bucket.getDocCount());
    		}
    
    		Avg balanceAgg1 = aggregations.get("balanceAgg");
    		System.out.println("平均薪资:" + balanceAgg1.getValue());
    
    	}
    
    • 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
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
  • 相关阅读:
    总体设计(一)
    毕业论文外文文献在哪里找?
    Spring Security详细讲解(JWT+SpringSecurity登入案例)
    C++ 动态库热加载
    ubus调试小结
    keycloak~对接login-status-iframe页面判断用户状态变更
    20和遍历以及迭代器有关的一些东西
    OpenLayers线性渐变和中心渐变(径向渐变)
    Python3 输入和输出
    pip助手2.0.0发布
  • 原文地址:https://blog.csdn.net/weixin_41365204/article/details/134418753