热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

ElasticSearch全文检索

1.ElasticSearch-全文检索1.1简介:Elasticsearch是一个分布式的开源搜索和分析引擎,在ApacheLucene的基础上开发而成。Lucene是开源的搜索

1.ElasticSearch-全文检索

1.1 简介:



  • Elasticsearch 是一个分布式的开源搜索和分析引擎,在 Apache Lucene 的基础上开发而成。Lucene 是开源的搜索引擎工具包,Elasticsearch 充分利用Lucene,并对其进行了扩展,使存储、索引、搜索都变得更快、更容易, 而最重要的是, 正如名字中的“ elastic ”所示, 一切都是灵活、有弹性的。而且,应用代码也不是必须用Java 书写才可以和Elasticsearc兼容,完全可以通过JSON 格式的HTTP 请求来进行索引、搜索和管理Elasticsearch 集群。



  • 官方文档:免费且开放的搜索:Elasticsearch、ELK 和 Kibana 的开发者 | Elastic




1.2 基本概念:



  • Index(索引)



    • 动词:相当于数据库中的insert



    • 名词:相当于数据库中的DataBase





  • Type(类型)



    • 在index索引中可以定义一个或多个类型,类似于Mysql中的table,每种类型的数据放在一起。





  • Document(文档)



    • 保存在某个索引(index)下,某种类型(type)的一个数据(Document),文档是JSON格式的,Document就像是Mysql中某个Table里面的内容。





  •  

     



 



  • 倒排索引:



    • ElasticSearch为什么能快速检索出我们所搜索得到内容,主要得益于其内部维护的倒排索引表:



    • 当保存第一条索引时,先对这条索引进行分词(定义见图片中,词也可以是单个字),在倒排索引表中记录每一个拆分出来的词的出现位置。保存完这五个索引就能维护出这样的一张倒排索引表。



    • 当我们想要检索红海特工行动时,一样先对检索的数据进行分词,在倒排索引表中发现红海出现在已保存的索引中的1,2,3,4,5.特工出现在5,行动出现在1,2,3.由于红海出现在了保存的所有的记录中,所以ElasticSearch会将保存的所有的数据都检索出来。红海和行动以及特工都分别出现了两次,谁排在前面涉及到相关性得分的高低。红海、行动在保存的记录中的命中率为2/2、2/3。红海和特工的命中率为2/4. 。自然红海和行动的相关性得分高,所以包含红海和行动的索引会排在包含红海和特工的索引的前面。





  •  

     




1.3 安装:


1.3.1 安装ElasticSearch:



  • 先将虚拟机内存增大至1G;



  • 启动vagrant,运行命令:



    • //安装elasticsearch
      sudo docker pull elasticsearch:7.4.2





1.3.2 安装可视化操作工具:



  • 运行命令:



    • //kibana
      sudo docker pull kibana:7.4.2





1.4 配置:


1.4.1 配置ElasticSearch



  • sudo docker images查看上面两个是否安装成功。



  • 创建配置文件夹及数据文件夹:



    • sudo mkdir -p /mydata/elasticsearch/config



    • sudo mkdir -p /mydata/elasticsearch/data



    • 如果已经是管理员就不用sudo了





  • 进入到mydata文件夹下并展示文件夹内容,查看elasticsearch文件夹是否创建成功



    • cd /mydata/



    • [vagrant@localhost mydata]$ ls 只用输入ls





  • 成功则进入到elasticsearch文件夹中并展示文件夹内容



    • [vagrant@localhost mydata]$ cd elasticsearch



    • [vagrant@localhost elasticsearch]$ ls 效果-》config data





  • 进入config文件夹中



    • [vagrant@localhost elasticsearch]$ cd config/





  • 切换root管理员模式



    • [vagrant@localhost config]$ su root 输入密码 默认是vagrant





  • 开始配置elasticsearch



    • [root@localhost config]# echo "http.host: 0.0.0.0" >> /mydata/elasticsearch/config/elasticsearch.yml
      [root@localhost config]# ls
      效果-》elasticsearch.yml
      [root@localhost config]# cat elasticsearch.yml
      效果-》http.host: 0.0.0.0
      [root@localhost config]# ll
      效果-》total 4
       -rw-r--r--. 1 root root 19 Aug 18 04:19 elasticsearch.yml




  • 启动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




  • docker ps 检测elasticsearch有没有启动,没有启动的话修改elasticsearch文件夹的权限,见下



  • cd ../返回上一层目录(elasticsearch),ll查看文件夹信息(效果及代码见下)



    • [root@localhost config]# cd ../
      [root@localhost elasticsearch]# ls
      config  data  plugins
      [root@localhost elasticsearch]# ll
      total 0
      drwxr-xr-x. 2 root root 31 Aug 18 04:19 config
      drwxr-xr-x. 2 root root  6 Aug 18 04:16 data
      drwxr-xr-x. 2 root root  6 Aug 18 04:53 plugins


    • 关于drwxr-xr-x的一点儿拓展



    •  

       



    • 所以对于elasticsearch这个文件夹,文件所有者具有全部权限,文件所属组具有执行和读权限,其他用户具有读权限。





  • 修改elasticsearch文件夹权限:



    • [root@localhost elasticsearch]# chmod -R 777 /mydata/elasticsearch/
      [root@localhost elasticsearch]# ll
      total 0
      drwxrwxrwx. 2 root root 31 Aug 18 04:19 config
      drwxrwxrwx. 2 root root  6 Aug 18 04:16 data
      drwxrwxrwx. 2 root root  6 Aug 18 04:53 plugins




  • docker ps -a 查看elasticsearch的CONTAINER ID,记录这个ID



  • 重启elasticsearch



    • [root@localhost elasticsearch]# docker start +你的ID的前几位(能与其他的服务ID区别开就行)





  • docker ps检测elasticsearch是否启动成功,docker logs +你的ID的前几位查看elasticsearch的日志有没有报错,没有报错就继续访问192.168.56.10:9200。能访问成功则表示elasticsearch配置成功!




1.4.2 运行Kibana:



  • 运行命令:



    • docker run --name kibana -e ELASTICSEARCH_HOSTS=http://192.168.56.10:9200 -p 5601:5601 -d kibana:7.4.2




  • docker ps检查kibana有没有成功启动



  • 访问http://192.168.56.10:5601检测kibana有没有成功启动,没有启动成功的话就看看日志。




1.4.3 设置kibana和ElasticSearch自启动



  • 运行命令:



    • sudo docker update cdae --restart=always
      sudo docker update 1754 --restart=always
      其中cdae和1754是你安装的kibana和ElasticSearch所对应的能够区分其他软件的ID。





1.5 elasticsearch入门


1.5.1 命令一 _cat:



  • GET/ _cat/nodes: 查看所有节点_



  • GET/ _cat/health : 查看es 健康状况_



  • GET/ _cat/master: 查看主节点_



  • GET/ _cat/indices: 查看所有索引 相当于sql里的 show databases;



  • postman 发送get请求访问 http://192.168.56.10:9200/_cat/nodes




1.5.2 命令二 post&put新增数据



  • put请求



    • 请求路径: 主机号+端口号+索引+类型+唯一标识。例:http://192.168.56.10:9200/customer/external/1,带上JSON数据。其中customer是索引,external是类型,1是保存的这条数据的唯一标识。



    • 注意:put请求必须带唯一标识。两次请求同一URL(唯一标识也相同),第一次为新增数据,第二次为修改数据。





  • post请求:



    • 请求路径:主机号+端口号+索引+类型。带上JSON数据



    • 注意:唯一标识可带可不带,不带唯一标识发送请求后elasticsearch会自动为你创建一个唯一标识,第二次发送同一请求一 样为新增操作,再一次为第二次请求创建唯一标识。带唯一标识就和put类似。





  •  

     



    • ”_index“:索引



    • ”_type":类型



    • "_id":唯一标识



    • "_verson":版本,随着这条记录的更新版本不断递加



    • "_shards":集群知识,目前不懂



    • "_seq_no":并发控制字段,每次更新就会加1,用来做乐观锁



    • "_primary_term":同上,主分配重新分配,如重启,就会变化。






1.5.3 命令三 get查询数据&乐观锁字段



  • get请求:



    • 请求路径:主机号+端口号+索引+类型+唯一标识





  • 乐观锁:



    • 如果两个人同时想修改同一条数据,很显然这是不允许的(数据库里的并发性控制也不允许),在发送的请求上带上参数_seq_no 和 _primary_term可以防止同时对同一条数据的误操作。(乐观锁)



    • 请去路径:http://192.168.56.10:9200/customer/external/1?if_seq_no=0&if_primary_term=1



    • 第一个人发送这个请求完成修改后,"_seq_no"的值就会发生变化,当第二个人后发送这个请求时,会显示409错误。



    •  

       



    •  

       






1.5.4 命令四 put&post修改数据



  • post请求更新:



    • 请求路径:主机号+端口号+索引+类型+唯一标识/_update



    • 当两次发送同一个post请求更新时,Elasticsearch会与原数据进行对比,没有变化则返回noop(NoOperation的缩写),同时版本号以及序列号(_seq_no)不会改变。



    • 注意:请求路径后带update,所带的JSON数据格式必须带doc。即:



      • {
           "doc":{
               "name":"TX",
               //可以继续新增数据
          }
        }


      • 请求路径后面不带update,多次重复发送同一请求Elasticsearch不会与原数据进行对比,版本号和序列号会递增。







  • put请求更新:



    • 请求路径:主机号+端口号+索引+类型+唯一标识



    • put更新操作不能带_update






1.5.5 命令五 删除数据



  • 删除数据:



    • 语法格式:DELETE customer/external/1 删除一条数据 or DELETE customer 删除整个索引



    • 没有对类型的删除



    • 请求方式为delete






1.5.6 命令六 bulk批量操作



  • bulk批量API



    • 请求路径:主机号+端口号+索引+类型+/_bulk



    • 请求方式必须为post。



    • 携带JSON数据的格式:



      • {action:{metadata}}
        {requestbody}

        eg:
        {"index":{"_id":1}}
        {"name":"TX"}
        {"index":{"_id":1}}
        {"name":"ZMY"}




    • postman中不支持批量操作,所以我们到Kibana((http://192.168.56.10:5601/app/kibana#/dev_tools/console?_g=()))中测试批量操作。



    • 测试数据网址:https://raw.githubusercontent.com/elastic/elasticsearch/7.4/docs/src/test/resources/accounts.json



    • 请求路径:POST /bank/account/_bulk






1.6 elasticsearch进阶


1.6.1 两种查询方式:



  • 使用REST request URL:查询条件写在url上



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




  • REST request body结构化查询:



    • GET bank/_search
      {
       "query": {
         "match_all": {}
      },
       "sort": [
        {
           "account_number": "asc"
        },
        {
           "balance": "desc"
        }
      ]
      }





1.6.2 QueryDSL的基本使用:



  • 标准语法(按提示)
    GET bank/_search
    {
     "query": {
       "match_all": {}
    },
     "sort": [
      {
         "balance": {
           "order": "desc"
        }
      }
    ],
     "from": 0,
     "size": 20,
     "_source": ["balance","firstname"]
    }


  • "_source":用来指定查询到的索引中返回的源数据的返回值,["balance","firstname"]表示在源数据中只显示balance和firstname这两个字段,只想返回一个字段也可以用{“字段名”}。




1.6.3 match全文检索



  • 全文检索会对检索条件进行分词匹配,按照评分进行排序。



  • match可以做精确检索也可以做模糊检索,字段名对应的检索条件是精确的,这次查询就为精确查询,反之为模糊查询。



    • GET bank/_search
      {
       "query": {
         "match": {
           "address": "Mill"
        }
      }
      }





1.6.4 match_phrase短语匹配:



  • match是将需要检索的词进行分词(拆词)匹配,而match_phrase则是将需要检索的词当作一个整体来匹配。



  • 语法:



    • GET bank/_search
      {
       "query": {
         "match_phrase": {
           "需要进行模糊匹配的字段名": "匹配值"
        }
      }
      }





1.6.5 multi_match 多字段匹配:



  • 类似于sql里面的username like··· or nickname like···



  • 语法:



    • 用在上面就相当于
      GET bank/_search
      {
       "query": {
         "multi_match": {
           "query": "省略号里面的东西",
           "fields": ["username","nickname"]
        }
      }
      }




  • multi_match 多字段匹配是分词匹配的,假设 省略号里面的东西 为A B,那么elasticsearch会将在username和nickname中包含A或B的索引全部都查出来,而同时包括A和B的相关性得分可能会更高。




1.6.6 bool 复合查询:



  • 用bool可以在一次查询中关联多个条件:



  • eg:



    • GET bank/_search
      {
       "query": {
         "bool": {
           "must": [
            {"match": {
               "FIELD": "TEXT"
            }}
          ],
           "must_not": [
            {"match": {
               "FIELD": "TEXT"
            }}
          ],
           "should": [
            {"match": {
               "FIELD": "TEXT"
            }}
          ]
        }
         
      }
      }


    • 其中must条件为某个字段必须是查询的值,must_not条件为某个字段必须不是查询的值,不影响相关性得分。should条件为某个字段可以是查询的值,也可以不是,是查询的值相关性得分更高。






1.6.7 filter过滤:



  • filter过滤器可以替代查询,但是filter不会计算相关性得分。



  • 语法:



    • GET bank/_search
      {
       "query": {
         "bool": {
           "must": [
            {"match": {
               "FIELD": "TEXT"
            }}
          ],
           "filter": {
             "range": {
               "FIELD": {
                 "gte": 10,
                 "lte": 20
              }
            }
          }
        }
         
      }
      }





1.6.8 term



  • 和match一样。匹配某个属性的值。全文检索字段用match,其他非text字段匹配用term。



  • GET bank/_search
    {
     "query": {
       "match": {
         "address.keyword": "TEXT"
      }
    }
    }


    GET bank/_search
    {
     "query": {
       "match_phrase": {
         "address": "TEXT"
      }
    }
    }


  • 这两种写法的不同之处:



    • 第一种写法是将address.keyword是将后面的TEXT值完全当作源数据中对应字段的值进行匹配。是一种精确匹配。



    • 第二种写法可以进行分词匹配,即源数据字段值中只需要含有这个值就行。






1.6.9 aggregations(执行聚合):



  • 聚合的基本使用:



    • GET bank/_search
      {
         "query": {
           "match": {
             "address": "mill"
          }
        },
         "aggs": {
           "AgeAggs": {
             "terms": {
               "field": "age",
               "size": 10
            }
          }
        }
      }


    • 聚合结果:



    • "aggregations" : {
       "AgeAggs" : {
         "doc_count_error_upper_bound" : 0,
         "sum_other_doc_count" : 0,
         "buckets" : [
          {
             "key" : 38,
             "doc_count" : 2
          },
          {
             "key" : 28,
             "doc_count" : 1
          },
          {
             "key" : 32,
             "doc_count" : 1
          }
        ]
      }
      }


    • 类似于sql中的聚合函数。



    • 先查询再聚合,上面的聚合的意思是按照年龄的值进行聚合。





  • 复杂聚合的使用:



    • GET bank/_search
      {
       "query": {
         "match_all": {}
      },
       "aggs": {
         "AgeAggs": {
           "terms": {
             "field": "age",
             "size": 100
          },
           "aggs": {
             "genderAgg": {
               "terms": {
                 "field": "gender.keyword",
                 "size": 10
              },
               "aggs": {
                 "balanceAvg": {
                   "avg": {
                     "field": "balance"
                  }
                }
              }
            }
          }
        }
      }
      }


    • 聚合中嵌套聚合(子聚合):先查询出所有的索引。先按照年龄聚合-》再在年龄聚合里按照性别聚合-》最后计算完成聚合后的分组的平均薪资。






1.6.10 参考:



  • 聚合的类型等等参考官网文档:Welcome to Elastic Docs | Elastic




1.6.11 映射:



  • 类似于sql里面的数据类型,不过在es里,新建某一条记录后es会为我们自动猜测并存储这条记录的类型



  • 使用 " GET /bank/_mapping "可以查看bank下的属性所对应的类型



  • 自定义映射类型(创建映射):



    • PUT /my_index
      {
       "mappings": {
         "properties": {
           "name": {
             "type": "text"
          },
           "age": {
             "type": "integer"
          },
           "email": {
             "type": "keyword"
          }
        }
      }
      }


    • text类型在检索时会进行全文检索,并且进行分词匹配。



    • keyword类型为精确检索。不进行分词匹配。





  • 为映射添加新的字段:



    • PUT /my_index/_mapping
      {
       "properties": {
         "employee_id": {
           "type": "keyword",
           "index": false
        }
      }
      }


    • 其中index默认值为true,决定这条记录能不能作为索引被检索。





  • 更新映射:



    • es里面不支持直接更新某个索引的映射,原因很简单。更新某个属性对应的类型后,之前所保存的属性的记录在检索时都会失效。对于已经存在的字段,我们不能更新。更新必须创建新的索引进行数据迁移。





  • 数据迁移:



    • es6.0之前:



      • PUT /newbank
        {
         "mappings": {
           "properties": {
             "account_number": {
               "type": "long"
            },
             "address": {
               "type": "text"
            },
             "age": {
               "type": "integer"
            },
             "balance": {
               "type": "long"
            },
             "city": {
               "type": "text"
            },
             "email": {
               "type": "text"
            },
             "employer": {
               "type": "text"
            },
             "firstname": {
               "type": "text"
            },
             "gender": {
               "type": "text"
            },
             "lastname": {
               "type": "text"
            },
             "state": {
               "type": "text"
            }
          }
        }
        }
        //创建新的索引

        GET /newbank/_mapping

        POST _reindex
        {
         "source": {
           "index": "bank",
           "type": "account"
        },
         "dest": {
           "index": "newbank "
        }
        }
        //数据迁移




    • es6.0之后:



      • 不需要指定数据类型



      • POST _reindex
        {
         "source": {
           "index": "bank"
        },
         "dest": {
           "index": "newbank "
        }
        }
        //数据迁移







1.6.12 分词:



  • 一个tokenizer(分词器)接收一个字符流,将之分割为独立的tokens(词元,通常是独立的单词),然后输出tokens流。

    例如:whitespace tokenizer遇到空白字符时分割文本。它会将文本“Quick brown fox!”分割为[Quick,brown,fox!]。

    该tokenizer(分词器)还负责记录各个terms(词条)的顺序或position位置(用于phrase短语和word proximity词近邻查询),以及term(词条)所代表的原始word(单词)的start(起始)和end(结束)的character offsets(字符串偏移量)(用于高亮显示搜索的内容)。

    elasticsearch提供了很多内置的分词器,可以用来构建custom analyzers(自定义分词器)。

    关于分词器: https://www.elastic.co/guide/en/elasticsearch/reference/7.6/analysis.html



  • 安装ik分词器:



    • 如果你的虚拟机能够连接外网,那就直接使用wget安装:



    • 没有安装wget先安装wget,顺便安装unzip 使用命令 :



      • yum -y install wget
        yum -y install unzip








  • 安装ik分词器方法一:(推荐)



    • 先进入 cd /mydata/elasticsearch/plugins/ik/



    • 使用命令:wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.4.2/elasticsearch-analysis-ik-7.4.2.zip 下载ik分词器7.4.2版本 (注意:这里的版本要和你所使用的elasticsearch的版本一致



    • 使用命令:unzip elasticsearch-analysis-ik-7.4.2.zip -d ik 解压下载的自拍文件。



    • 使用命令:rm -rf elasticsearch-analysis-ik-7.4.2.zip 删除压缩包文件。



    • 重启elastic search,去kimaba上测试ik分词器是否生效。





  • 安装ik分词器方法二:



    • 在github上找自己使用的elasticsearch对应的ik分词器的版本,下载并解压。



    • 使用虚拟机可视化操作软件比如MobaXterm在mydata/elasticsearch/plugins 下创建文件夹,取名ik,并利用MobaXterm在ik文件夹下上传你上一步解压的所有文件。



    • 测试。。。。。。





  • 配置nginx:



    • 随便启动一个nginx实例,只是为了复制出配置

      docker run -p 8081:80 --name nginx -d nginx:1.10  


    • 将容器内的配置文件拷贝到/mydata/nginx/conf/ 下

      mkdir -p /mydata/nginx/html
      mkdir -p /mydata/nginx/logs
      mkdir -p /mydata/nginx/conf
      docker container cp nginx:/etc/nginx .  #拷贝到当前文件夹
      #由于拷贝完成后会在config中存在一个nginx文件夹,所以需要将它的内容移动到conf中
      mv /mydata/nginx/conf/nginx/* /mydata/nginx/conf/
      rm -rf /mydata/nginx/conf/nginx


    • 终止原容器:

      docker stop nginx


    • 执行命令删除原容器:

      docker rm nginx


    • 创建新的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


    • 设置开机启动nginx

      docker update nginx --restart=always

       



    • 创建“/mydata/nginx/html/index.html”文件,测试是否能够正常访问

      echo '

      hello nginx!

      ' >/mydata/nginx/html/index.html

      访问:http://ngix所在主机的IP:80/index.html





  • 自定义词库:



    • 方法一:通过nginx 间接自定义词库:



      • 在 /mydata/nginx/html/es/ 定义一个txt文件作为词库文件



      • 修改 /mydata/elasticsearch/plugins/ik/config/ IKAnalyzer.cfg/xml ,设置远程词库为192.168.56.10/es/fenci.txt 也就是你之前创建词库文件的位置。



      • 重启elastic search,测试效果。





    • 方法二:通过ik分词器中的config配置文件定义词库:



      • 在/mydata/elasticsearch/plugins/ik/config/ 目录下新建一个fenci.dic文件。



      • 修改 /mydata/elasticsearch/plugins/ik/config/ IKAnalyzer.cfg.xml ,设置扩展字典为fenci.dic。也就是你刚刚创建词库文件。



      • 重启elastic search,测试效果。





    • 这两种方法根本原理都相同,都是在某个文件中添加你想保留的字段,让分词器在分词时根据你的设置来进行分词。



    • IKAnalyzer.cfg.xml






      • IK Analyzer 扩展配置

        fenci.dic



        http://192.168.56.10/es/fenci.txt










1.7 Elasticearch-Rest-Client


1.7.1 9300: TCP



  • spring-data-elasticsearch:transport-api.jar;



    • springboot版本不同,ransport-api.jar不同,不能适配es版本



    • 7.x已经不建议使用,8以后就要废弃






1.7.2 9200: HTTP



  • jestClient: 非官方,更新慢;



  • RestTemplate:模拟HTTP请求,ES很多操作需要自己封装,麻烦;



  • HttpClient:同上;



  • Elasticsearch-Rest-Client:官方RestClient,封装了ES操作,API层次分明,上手简单; 最终选择Elasticsearch-Rest-Client(elasticsearch-rest-high-level-client); https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high.html




1.8 springboot整合Elastic Search:


1.8.1 导入依赖:



  • 新建module、开启服务注册发现什么的自己来。



  • 依赖版本要和自己的elasticsearch的版本一致。



  • org.elasticsearch.client elasticsearch-rest-high-level-client 7.4.2



  • 父依赖中的elasticsearch版本要修改为对应的版本。(不该后面会报错)



    • 7.4.2





1.8.2 测试保存数据



  • @RunWith(SpringRunner.class)
    @SpringBootTest
    class GulimallSearchApplicationTests {

       @Resource
       RestHighLevelClient restHighLevelClient;
       @Test
       void contextLoads() {
          System.out.println(restHighLevelClient);
      }
       @Test
       void initData() throws IOException {
           IndexRequest indexRequest=new IndexRequest("user");
           indexRequest.id("1");
           //初始化数据
           User user=new User();
           user.setName("张满月");
           user.setAge(20);
           user.setSex("女");
           //将数据转化成json格式
           String jsOnString= JSON.toJSONString(user);
           indexRequest.source(jsonString, XContentType.JSON);
           //同步执行操作
           IndexResponse indexRespOnse= restHighLevelClient.index(indexRequest,GulimallElasticSearchConfig.COMMON_OPTIONS);
           //提取有用的相应数据
           System.out.println(indexResponse);
      }
       @Data
       public class User{
           private String name;
           private String sex;
           private int age;
      }

    }



1.8.3 测试获取数据

https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high-search.html

  @Test
  public void searchData() throws IOException {
      GetRequest getRequest = new GetRequest(
              "users",
              "_-2vAHIB0nzmLJLkxKWk");

      GetResponse getRespOnse= client.get(getRequest, RequestOptions.DEFAULT);
      System.out.println(getResponse);
      String index = getResponse.getIndex();
      System.out.println(index);
      String id = getResponse.getId();
      System.out.println(id);
      if (getResponse.isExists()) {
          long version = getResponse.getVersion();
          System.out.println(version);
          String sourceAsString = getResponse.getSourceAsString();
          System.out.println(sourceAsString);
          Map sourceAsMap = getResponse.getSourceAsMap();
          System.out.println(sourceAsMap);
          byte[] sourceAsBytes = getResponse.getSourceAsBytes();
      } else {

      }
  }

查询state="AK"的文档:

{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 22,   //匹配到了22条
"relation": "eq"
},
"max_score": 3.7952394,
"hits": [{
"_index": "bank",
"_type": "account",
"_id": "210",
"_score": 3.7952394,
"_source": {
"account_number": 210,
"balance": 33946,
"firstname": "Cherry",
"lastname": "Carey",
"age": 24,
"gender": "M",
"address": "539 Tiffany Place",
"employer": "Martgo",
"email": "cherrycarey@martgo.com",
"city": "Fairacres",
"state": "AK"
}
},
          ....//省略其他
        ]
}
}

搜索address中包含mill的所有人的年龄分布以及平均年龄,平均薪资

GET bank/_search
{
 "query": {
   "match": {
     "address": "Mill"
  }
},
 "aggs": {
   "ageAgg": {
     "terms": {
       "field": "age",
       "size": 10
    }
  },
   "ageAvg": {
     "avg": {
       "field": "age"
    }
  },
   "balanceAvg": {
     "avg": {
       "field": "balance"
    }
  }
}
}

java实现

   /**
    * 复杂检索:在bank中搜索address中包含mill的所有人的年龄分布以及平均年龄,平均薪资
    * @throws IOException
    */
   @Test
   public void searchData() throws IOException {
       //1. 创建检索请求
       SearchRequest searchRequest = new SearchRequest();

       //1.1)指定索引
       searchRequest.indices("bank");
       //1.2)构造检索条件
       SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
       sourceBuilder.query(QueryBuilders.matchQuery("address","Mill"));

       //1.2.1)按照年龄分布进行聚合
       TermsAggregationBuilder ageAgg=AggregationBuilders.terms("ageAgg").field("age").size(10);
       sourceBuilder.aggregation(ageAgg);

       //1.2.2)计算平均年龄
       AvgAggregationBuilder ageAvg = AggregationBuilders.avg("ageAvg").field("age");
       sourceBuilder.aggregation(ageAvg);
       //1.2.3)计算平均薪资
       AvgAggregationBuilder balanceAvg = AggregationBuilders.avg("balanceAvg").field("balance");
       sourceBuilder.aggregation(balanceAvg);

       System.out.println("检索条件:"+sourceBuilder);
       searchRequest.source(sourceBuilder);
       //2. 执行检索
       SearchResponse searchRespOnse= client.search(searchRequest, RequestOptions.DEFAULT);
       System.out.println("检索结果:"+searchResponse);

       //3. 将检索结果封装为Bean
       SearchHits hits = searchResponse.getHits();
       SearchHit[] searchHits = hits.getHits();
       for (SearchHit searchHit : searchHits) {
           String sourceAsString = searchHit.getSourceAsString();
           Account account = JSON.parseObject(sourceAsString, Account.class);
           System.out.println(account);

      }

       //4. 获取聚合信息
       Aggregations aggregatiOns= searchResponse.getAggregations();

       Terms ageAgg1 = aggregations.get("ageAgg");

       for (Terms.Bucket bucket : ageAgg1.getBuckets()) {
           String keyAsString = bucket.getKeyAsString();
           System.out.println("年龄:"+keyAsString+" ==> "+bucket.getDocCount());
      }
       Avg ageAvg1 = aggregations.get("ageAvg");
       System.out.println("平均年龄:"+ageAvg1.getValue());

       Avg balanceAvg1 = aggregations.get("balanceAvg");
       System.out.println("平均薪资:"+balanceAvg1.getValue());


  }  

可以尝试对比打印的条件和执行结果,和前面的ElasticSearch的检索语句和检索结果进行比较;

 


其他


1. kibana控制台命令

ctrl+home:回到文档首部;

ctril+end:回到文档尾部。


 

 

 



推荐阅读
  • ABP框架是ASP.NET Boilerplate的简称,它不仅是一个开源且文档丰富的应用程序框架,还提供了一套基于领域驱动设计(DDD)的最佳实践架构模型。本文将详细介绍ABP框架的特点、项目结构及其在Web API优先架构中的应用。 ... [详细]
  • 本文回顾了作者在求职阿里和腾讯实习生过程中,从最初的迷茫到最后成功获得Offer的心路历程。文中不仅分享了个人的面试经历,还提供了宝贵的面试准备建议和技巧。 ... [详细]
  • [附源码]计算机毕业设计JAVAjsp医药管理信息系统
    [附源码]计算机毕业设计JAVAjsp医药管理信息系统项目运行环境配置:Jdk1.8Tomcat7.0MysqlHBuilderX(Webstor ... [详细]
  • Python3爬虫入门:pyspider的基本使用[python爬虫入门]
    Python学习网有大量免费的Python入门教程,欢迎大家来学习。本文主要通过爬取去哪儿网的旅游攻略来给大家介绍pyspid ... [详细]
  • 本文探讨了如何在PHP与MySQL环境中实现高效的分页查询,包括基本的分页实现、性能优化技巧以及高级的分页策略。 ... [详细]
  • 入门指南:使用FastRPC技术连接Qualcomm Hexagon DSP
    本文旨在为初学者提供关于如何使用FastRPC技术连接Qualcomm Hexagon DSP的基础知识。FastRPC技术允许开发者在本地客户端实现远程调用,从而简化Hexagon DSP的开发和调试过程。 ... [详细]
  • 实践指南:使用Express、Create React App与MongoDB搭建React开发环境
    本文详细介绍了如何利用Express、Create React App和MongoDB构建一个高效的React应用开发环境,旨在为开发者提供一套完整的解决方案,包括环境搭建、数据模拟及前后端交互。 ... [详细]
  • 本文旨在探讨设计模式在Visual FoxPro (VFP) 中的应用可能性。虽然VFP作为一种支持面向对象编程(xbase语言)的工具,其OO特性相对简明,缺乏高级语言如Java、C++等提供的复杂特性,但设计模式作为一种通用的解决方案框架,是否能有效应用于VFP,值得深入研究。 ... [详细]
  • 在Java开发中,保护代码安全是一个重要的课题。由于Java字节码容易被反编译,因此使用代码混淆工具如ProGuard变得尤为重要。本文将详细介绍如何使用ProGuard进行代码混淆,以及其基本原理和常见问题。 ... [详细]
  • Django与Python及其他Web框架的对比
    本文详细介绍了Django与其他Python Web框架(如Flask和Tornado)的区别,并探讨了Django的基本使用方法及与其他语言(如PHP)的比较。 ... [详细]
  • 对象存储与块存储、文件存储等对比
    看到一篇文档,讲对象存储,好奇,搜索文章,摘抄,学习记录!背景:传统存储在面对海量非结构化数据时,在存储、分享与容灾上面临很大的挑战,主要表现在以下几个方面:传统存储并非为非结 ... [详细]
  • 在开发板的启动选项中看到如下两行:7:LoadBootLoadercodethenwritetoFlashviaSerial.9:LoadBootLoadercodethenwri ... [详细]
  • ElasticSerach初探第一篇认识ES+环境搭建+简单MySQL数据同步+SpringBoot整合ES
    一、认识ElasticSearch是一个基于Lucene的开源搜索引擎,通过简单的RESTfulAPI来隐藏Lucene的复杂性。全文搜索,分析系统&# ... [详细]
  • 部署solr建立nutch索引
    2019独角兽企业重金招聘Python工程师标准接着上篇nutch1.4的部署应用,我们来部署一下solr,solr是对lucene进行了封装的企 ... [详细]
  • 本文提供了一种有效的方法来解决当Android Studio因电脑意外重启而导致的所有import语句出现错误的问题。通过清除缓存和重建项目结构,可以快速恢复开发环境。 ... [详细]
author-avatar
同步管理精英
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有