使用 Docker 安装

  • 拉取镜像 ```shell

    存储和检索数据

    $ docker pull elasticsearch:7.4.2

可视化检索数据,非必需

$ docker pull kibana:7.4.2

  1. - 使用 docker-compose 创建容器
  2. ```shell
  3. version: "2"
  4. services:
  5. DOClever:
  6. image: elasticsearch:7.4.2
  7. restart: always
  8. container_name: "elasticsearch"
  9. ports:
  10. - 9200:9200
  11. - 9300:9300
  12. environment:
  13. - ES_JAVA_OPTS=-Xms64m -Xmx512m # 注意设置占用内存大小,否则可能机器内存不足启动不了
  14. - "discovery.type=single-node"
  15. kibana:
  16. image: kibana:7.4.2
  17. restart: always
  18. container_name: "kibana"
  19. ports:
  20. - 5601:5601
  21. environment:
  22. - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
  • 启动容器
    1. docker-compose up -d

    基本概念

    Elasticsearch 是面向文档型数据库,一条数据在这里就是一个文档。为了方便理解,我们将 Elasticsearch 里存储文档数据和关系型数据库 MySQL 存储数据的概念进行一个类比:
    image.png
    ES 里的 Index 可以看做一个库,而 Types 相当于表,Documents 则相当于表的行。这里 Types 的概念已经被逐渐弱化,Elasticsearch 6.X 中,一个 index 下已经只能包含一个 type,Elasticsearch 7.X 中, Type 的概念已经被删除了。

    基本操作

    查看服务状态与信息

    ```shell

    查看所有节点

    GET _cat/nodes

查看健康状态

GET _cat/health

查看主节点

GET _cat/master

  1. <a name="j8i6u"></a>
  2. ### 索引的增删改查
  3. ```shell
  4. # 创建一个名为 product 的索引
  5. PUT product
  6. # 查看所有索引,?v 的作用是让返回的数据格式更方便查看
  7. GET _cat/indices?v
  8. # 查看名为 product 的索引
  9. GET _cat/indices/product?v
  10. GET product
  11. # 删除名为 product 的索引
  12. DELETE product

增删改文档

  1. # 不指定 id 的创建方式,自动生成一个随机 id
  2. POST product/_doc
  3. {
  4. "title": "小米手机",
  5. "category": "小米",
  6. "images": "http://www.gulixueyuan.com/xm.jpg",
  7. "price": 3999
  8. }
  9. # 指定 id,如果 id 存在则会修改这个数据,版本号加 1
  10. POST product/_doc/1
  11. {
  12. "title": "小米手机",
  13. "category": "小米",
  14. "images": "http://www.gulixueyuan.com/xm.jpg",
  15. "price": 3999
  16. }
  17. # 只修改指定的字段
  18. POST product/_update/1
  19. {
  20. "doc": {
  21. "price": 2000
  22. }
  23. }
  24. # PUT 请求也可以新增或修改数据,但 PUT 必须指定 id,所以一般使用 PUT 修改数据
  25. PUT product/_doc/1
  26. {
  27. "title": "小米手机 new",
  28. "category": "小米",
  29. "images": "http://www.gulixueyuan.com/xm.jpg",
  30. "price": 3999
  31. }
  32. # 根据 id 删除文档
  33. DELETE product/_doc/1
  34. # 根据条件删除文档(删除 price 为 2000 的文档)
  35. POST product/_delete_by_query
  36. {
  37. "query": {
  38. "match": {
  39. "price": 2000
  40. }
  41. }
  42. }

根据 id 查看文档数据

  1. # 根据主键获取文档数据
  2. GET product/_doc/1

检索信息 Query DSL 语法

Elasticsearch 提供了一个可以执行查询的 Json 风格的 DSL(domain-specific language 领域特 定语言)。这个被称为 Query DSL。该查询语言非常全面,并且刚开始的时候感觉有点复杂, 真正学好它的方法是从一些基础的示例开始的。
推荐阅读官方文档:https://www.elastic.co/guide/cn/elasticsearch/guide/current/search-in-depth.html
image.png
导入测试数据:
https://github.com/elastic/elasticsearch/blob/master/docs/src/test/resources/accounts.json

query查询基本语法

  1. # 检索数据
  2. # query 定义如何查询
  3. # match_all 查询类型(代表查询所有的所有),es 中可以在 query 中组合非常多的查询类型完成复杂查询
  4. # 除了 query 参数之外,我们也可以传递其它的参数以改变查询结果。如 sort、size,可以用 from + size 实现分页
  5. # sort 排序,多字段排序,会在前序字段相等时后续字段内部排序,否则以前序为准
  6. GET bank/_search
  7. {
  8. "query": {
  9. "match_all": {}
  10. }
  11. }

返回部分字段

  1. # _source 定义返回部分字段
  2. GET bank/_search
  3. {
  4. "query": {
  5. "match_all": {}
  6. },
  7. "_source": [
  8. "balance",
  9. "firstname"
  10. ]
  11. }

match 匹配查询

  1. ## match 匹配查询
  2. GET bank/_search
  3. {
  4. "query": {
  5. "match": {
  6. "account_number": 20
  7. }
  8. },
  9. "_source": [
  10. "balance",
  11. "firstname",
  12. "account_number"
  13. ]
  14. }
  15. # match 字符串,全文检索,查询出 address 包含 mill 的记录
  16. GET bank/_search
  17. {
  18. "query": {
  19. "match": {
  20. "address": "mill"
  21. }
  22. },
  23. "_source": [
  24. "address",
  25. "firstname",
  26. "account_number"
  27. ]
  28. }
  29. # 字符串,多个单词(分词+全文检索),查询出 address 包含 mill 和 road 的记录,并给出相关性得分
  30. GET bank/_search
  31. {
  32. "query": {
  33. "match": {
  34. "address": "mill road"
  35. }
  36. },
  37. "_source": [
  38. "address",
  39. "firstname",
  40. "account_number"
  41. ]
  42. }

match_phrase 短语匹配,不分词

  1. # 短语匹配,不分词
  2. GET bank/_search
  3. {
  4. "query": {
  5. "match_phrase": {
  6. "address": "mill road"
  7. }
  8. },
  9. "_source": [
  10. "address",
  11. "firstname",
  12. "account_number"
  13. ]
  14. }

multi_match 多字段匹配

  1. # multi_match 多字段匹配,查询 state 或者 address 包含 mill 的记录
  2. GET bank/_search
  3. {
  4. "query": {
  5. "multi_match": {
  6. "query": "mill",
  7. "fields": [
  8. "state",
  9. "address"
  10. ]
  11. }
  12. },
  13. "_source": [
  14. "address",
  15. "firstname",
  16. "state"
  17. ]
  18. }

bool 复合查询

  1. # bool 复合查询
  2. # 复合语句可以合并任何其它查询语句,包括复合语句,了解这一点是很重要的
  3. # 这就意味着复合语句之间可以互相嵌套,可以表达非常复杂的逻辑
  4. # must:必须达到must列举的所有条件
  5. # should:应该达到should列举的条件,如果达到会增加相关文档的评分,并不会改变 查询的结果。
  6. # 如果 query 中只有 should 且只有一种匹配规则,那么 should 的条件就会被作为默认匹配条而改变查询结果
  7. GET bank/_search
  8. {
  9. "query": {
  10. "bool": {
  11. "must": [
  12. {
  13. "match": {
  14. "address": "mill"
  15. }
  16. },
  17. {
  18. "match": {
  19. "gender": "M"
  20. }
  21. }
  22. ],
  23. "should": [
  24. {
  25. "match": {
  26. "address": "lane"
  27. }
  28. }
  29. ],
  30. "must_not": [
  31. {
  32. "match": {
  33. "email": "baluba.com"
  34. }
  35. }
  36. ]
  37. }
  38. }
  39. }

filter 结果过滤

  1. # 并不是所有的查询都需要产生分数,特别是那些仅用于 “filtering”(过滤)的文档
  2. # 为了不计算分数 Elasticsearch 会自动检查场景并且优化查询的执行
  3. GET bank/_search
  4. {
  5. "query": {
  6. "bool": {
  7. "must": [
  8. {
  9. "match": {
  10. "address": "mill"
  11. }
  12. }
  13. ],
  14. "filter": {
  15. "range": {
  16. "balance": {
  17. "gte": 10000,
  18. "lte": 20000
  19. }
  20. }
  21. }
  22. }
  23. },
  24. "_source": [
  25. "balance",
  26. "address"
  27. ]
  28. }

term

  1. ### term 和 match 一样。匹配某个属性的值。全文检索字段用 match,其他非 text 字段匹配用 term,这是一个规范
  2. GET bank/_search
  3. {
  4. "query": {
  5. "bool": {
  6. "must": [
  7. {
  8. "term": {
  9. "age": {
  10. "value": "28"
  11. }
  12. }
  13. }
  14. ]
  15. }
  16. }
  17. }

aggregations 聚合

  1. ### 搜索 address 中包含 mill 的所有人的年龄分布以及平均年龄,但不显示这些人的详情
  2. GET bank/_search
  3. {
  4. "query": {
  5. "match": {
  6. "address": "mill"
  7. }
  8. },
  9. "aggs": {
  10. "group_by_state": {
  11. "terms": {
  12. "field": "age"
  13. }
  14. },
  15. "avg_age": {
  16. "avg": {
  17. "field": "age"
  18. }
  19. }
  20. },
  21. "size": 0
  22. }
  23. # 按照年龄聚合,并且请求这些年龄段的这些人的平均薪资
  24. GET bank/_search
  25. {
  26. "query": {
  27. "match_all": {}
  28. },
  29. "aggs": {
  30. "ageAgg": {
  31. "terms": {
  32. "field": "age",
  33. "size": 1000
  34. },
  35. "aggs": {
  36. "balanceAvg": {
  37. "avg": {
  38. "field": "balance"
  39. }
  40. }
  41. }
  42. }
  43. }
  44. }
  45. # 查出所有年龄分布,并且这些年龄段中 M 的平均薪资和 F 的平均薪资以及这个年龄段的总体平均薪资
  46. GET bank/_search
  47. {
  48. "query": {
  49. "match_all": {}
  50. },
  51. "aggs": {
  52. "ageAgg": {
  53. "terms": {
  54. "field": "age"
  55. },
  56. "aggs": {
  57. "genderAgg": {
  58. "terms": {
  59. "field": "gender.keyword",
  60. "size": 5
  61. },
  62. "aggs": {
  63. "balanveAvg": {
  64. "avg": {
  65. "field": "balance"
  66. }
  67. }
  68. }
  69. },
  70. "ageBalanceAvg": {
  71. "avg": {
  72. "field": "balance"
  73. }
  74. }
  75. }
  76. }
  77. }
  78. }

Mapping 字段类型

映射

Mapping 是用来定义一个文档(document),以及它所包含的属性(field)是如何存储和 索引的。比如,使用 mapping 来定义:

  • 哪些字符串属性应该被看做全文本属性(full text fields)
  • 哪些属性包含数字,日期或者地理位置
  • 文档中的所有属性是否都能被索引(_all 配置)
  • 日期的格式
  • 自定义映射规则来执行动态添加属性

    新版本改变

    ES7 及以上移除了 type 的概念。
    关系型数据库中两个数据表示是独立的,即使他们里面有相同名称的列也不影响使用,但 ES 中不是这样的。elasticsearch 是基于 Lucene 开发的搜索引擎,而 ES 中不同 type 下名称相同的 filed 最终在 Lucene 中的处理方式是一样的。
    两个不同 type 下的两个 user_name,在 ES 同一个索引下其实被认为是同一个 filed,你必须在两个不同的 type 中定义相同的 filed 映射。否则,不同 type 中的相同字段名称就会在处理中出现冲突的情况,导致 Lucene 处理效率下降。
    去掉 type 就是为了提高 ES 处理数据的效率。

  • Elasticsearch 7.x

URL中的type参数为可选。比如,索引一个文档不再要求提供文档类型。

  • Elasticsearch 8.x

不再支持URL中的type参数。

  • 解决方法:

将索引从多类型迁移到单类型,每种类型文档一个独立索引,将已存在的索引下的类型数据,全部迁移到指定位置即可,详见数据迁移。

Mapping 类型

  • type:类型
    • String:分为两种,text:可分词;keyword:不可分词,数据会作为完整字段进行匹配
    • Numerical:数值类型,分两类,基本数据类型:long、integer、short、byte、double、float、 half_float;浮点数的高精度类型:scaled_float
    • Date:日期类型
    • Array:数组类型
    • Object:对象
  • index:是否索引,默认为 true,也就是说你不进行任何配置,所有字段都会被索引。true:字段会被索引,则可以用来进行搜索,false:字段不会被索引,不能用来搜索。
  • store:是否将数据进行独立存储,默认为 false,原始的文本会存储在_source 里面,默认情况下其他提取出来的字段都不是独立存储的,是从_source 里面提取出来的。当然也可以独立的存储某个字段,只要设置”store”: true 即可,获取独立存储的字段要比从_source 中解析快得多,但是也会占用更多的空间,所以要根据实际业务需求来设置。
  • analyzer:分词器。

    Mapping 基本操作

    查看索引的 mapping 信息

    1. # 查看 product 索引的 mapping 信息
    2. GET product/_mapping

    创建 mapping

    1. PUT product
    2. {
    3. "mappings": {
    4. "properties": {
    5. "age": {
    6. "type": "integer"
    7. },
    8. "email": {
    9. "type": "keyword"
    10. },
    11. "name": {
    12. "type": "text"
    13. }
    14. }
    15. }
    16. }

    添加新的字段 mapping

    1. # 添加新的字段 mapping
    2. PUT product2/_mapping
    3. {
    4. "properties": {
    5. "price": {
    6. "type": "integer"
    7. }
    8. }
    9. }

    更新 mapping

    对于已经存在的 mapping,不能对它进行更新,只能创建新的索引再进行数据迁移。

    数据迁移

  • 创建新索引,命名为 product2

    1. # 创建新索引,修改字段类型
    2. PUT product2
    3. {
    4. "mappings": {
    5. "properties": {
    6. "category": {
    7. "type": "text"
    8. },
    9. "images": {
    10. "type": "text"
    11. },
    12. "price": {
    13. "type": "half_float"
    14. },
    15. "title": {
    16. "type": "text"
    17. }
    18. }
    19. }
    20. }
  • 进行数据迁移,将 product 的数据迁移到 product2

    1. POST _reindex
    2. {
    3. "source": {
    4. "index":"product"
    5. },
    6. "dest": {
    7. "index": "product2"
    8. }
    9. }

    分词

    安装分词器

  • 下载分词器,版本要和 elasticsearch 一样:https://github.com/medcl/elasticsearch-analysis-ik/releases/tag/v7.4.2

  • 将下载的文件解压到 plugins,重启容器

    1. $ pwd
    2. /usr/share/elasticsearch/plugins
    3. $ ls
    4. elasticsearch-analysis-ik-7.4.2
  • 进行 bin 目录,查看插件是否安装成功 ```shell $ pwd /usr/share/elasticsearch/bin

$ ./elasticsearch-plugin list elasticsearch-analysis-ik-7.4.2

  1. <a name="c6849b04"></a>
  2. ### 测试分词器
  3. ```shell
  4. GET _analyze
  5. {
  6. "analyzer": "ik_smart",
  7. "text": ["尚硅谷电商项目", "苹果手机"]
  8. }
  9. GET _analyze
  10. {
  11. "analyzer": "ik_max_word",
  12. "text": ["尚硅谷电商项目", "苹果手机"]
  13. }

自定义词库

  • 增加本地词库

    /usr/share/elasticsearch/plugins/elasticsearch-analysis-ik-7.4.2/config/ext_dict.dic

  1. 尚硅谷
  2. 电商
  • 修改配置文件,加入在 key 为 ext_dict 的 entry 节点内容填上 ext_dict.dic

    /usr/share/elasticsearch/plugins/elasticsearch-analysis-ik-7.4.2/config/IKAnalyzer.cfg.xml

  1. <properties>
  2. <comment>IK Analyzer 扩展配置</comment>
  3. <!--用户可以在这里配置自己的扩展字典 -->
  4. <entry key="ext_dict">ext_dict.dic</entry>
  5. <!--用户可以在这里配置自己的扩展停止词字典-->
  6. <entry key="ext_stopwords"></entry>
  7. <!--用户可以在这里配置远程扩展字典 -->
  8. <!-- <entry key="remote_ext_dict">https://xxx.com/keyword/word.txt</entry>-->
  9. <!--用户可以在这里配置远程扩展停止词字典-->
  10. <!-- <entry key="remote_ext_stopwords">words_location</entry> -->
  11. </properties>
  • 重启容器即可,测试分词: ```shell GET _analyze

{ “analyzer”: “ik_max_word”, “text”: “尚硅谷电商项目” }

  1. 响应:
  2. ```shell
  3. {
  4. "tokens": [
  5. {
  6. "token": "尚硅谷",
  7. "start_offset": 0,
  8. "end_offset": 3,
  9. "type": "CN_WORD",
  10. "position": 0
  11. },
  12. {
  13. "token": "电商",
  14. "start_offset": 3,
  15. "end_offset": 5,
  16. "type": "CN_WORD",
  17. "position": 1
  18. },
  19. {
  20. "token": "项目",
  21. "start_offset": 5,
  22. "end_offset": 7,
  23. "type": "CN_WORD",
  24. "position": 2
  25. }
  26. ]
  27. }

Elasticsearch-Rest-Client

  • 9300端口

TCP 协议,适用于 spring data,spring-data-elasticsearch:transport-api.jar,spring boot 版本不同则 transport-api.jar 不同,不能适配 es 版本,
7.x已经不建议使用,8以后就要废弃

  • 9200端口

HTTP 协议,可使用多种 http 工具直接发送 http 请求

JestClient:非官方,更新慢
RestTemplate:模拟发HTTP请求,ES 很多操作需要自己封装,比较麻烦
HttpClient:同上
Elasticsearch-Rest-Client:官方 RestClient,封装了 ES 操作,API 层次分明,上手简单

最终选择 Elasticsearch-Rest-Client

文档地址:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high.html

image.png

spring boot 整合

  • pom.xml 加入依赖,注意版本要与 es 一致 ```xml …7.4.2

org.elasticsearch.client elasticsearch-rest-client ${elasticsearch.version} org.elasticsearch.client elasticsearch-rest-high-level-client ${elasticsearch.version}

org.elasticsearch elasticsearch ${elasticsearch.version}

  1. - 配置客户端 bean
  2. > com.atguigu.gulimall.search.config.GulimallElasticSearchConfig
  3. ```java
  4. @Configuration
  5. public class GulimallElasticSearchConfig {
  6. @Bean
  7. public RestHighLevelClient esRestClient() {
  8. return new RestHighLevelClient(RestClient.builder(new HttpHost("localhost", 9200, "http")));
  9. }
  10. }

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

索引的增删查操作

  • 创建索引

    1. public static void testCreateIndex() throws IOException {
    2. RestHighLevelClient esClient = createClient();
    3. CreateIndexRequest createIndexRequest = new CreateIndexRequest("user");
    4. CreateIndexResponse createIndexResponse = esClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
    5. boolean acknowledged = createIndexResponse.isAcknowledged();
    6. esClient.close();
    7. System.out.println("create index response: " + acknowledged);
    8. }
  • 获取索引

    1. public static void testGetIndex() throws IOException {
    2. RestHighLevelClient esClient = createClient();
    3. GetIndexRequest getIndexRequest = new GetIndexRequest("product");
    4. GetIndexResponse getIndexResponse = esClient.indices().get(getIndexRequest, RequestOptions.DEFAULT);
    5. esClient.close();
    6. System.out.println(getIndexResponse.getAliases());
    7. System.out.println(getIndexResponse.getMappings());
    8. }
  • 删除索引

    1. public static void testDeleteIndex() throws IOException {
    2. RestHighLevelClient esClient = createClient();
    3. DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest("user");
    4. AcknowledgedResponse acknowledgedResponse = esClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
    5. esClient.close();
    6. System.out.println("delete index response: " + acknowledgedResponse.isAcknowledged());
    7. }

    文档的增删改查操作

  • 创建文档 ```java public static void testCreateDoc() throws IOException { RestHighLevelClient esClient = createClient();

    IndexRequest indexRequest = new IndexRequest(); indexRequest.index(“user”).id(“1002”);

    HashMap map = new HashMap<>(); map.put(“name”, “jone”); map.put(“password”, “123”);

    indexRequest.source(JSON.toJSONString(map), XContentType.JSON); IndexResponse response = esClient.index(indexRequest, RequestOptions.DEFAULT); esClient.close();

    System.out.println(“create doc result: “ + response.getResult()); }

// 批量插入文档 public static void teatBatchCreateDoc() throws IOException { RestHighLevelClient esClient = createClient();

  1. BulkRequest bulkRequest = new BulkRequest();
  2. for (int i = 0; i < 10; i++) {
  3. IndexRequest indexRequest = new IndexRequest()
  4. .index("user")
  5. .id("100" + i)
  6. .source(XContentType.JSON, "name", "name:" + i, "password", "password:" + i);
  7. bulkRequest.add(indexRequest);
  8. }
  9. BulkResponse response = esClient.bulk(bulkRequest, RequestOptions.DEFAULT);
  10. System.out.println(response.getTook());
  11. System.out.println(Arrays.toString(response.getItems()));

}

  1. - 更新文档
  2. ```java
  3. public static void testUpdateDoc() throws IOException {
  4. RestHighLevelClient esClient = createClient();
  5. UpdateRequest updateRequest = new UpdateRequest();
  6. updateRequest.index("user").id("1001");
  7. updateRequest.doc(XContentType.JSON, "name", "jone nea");
  8. UpdateResponse response = esClient.update(updateRequest, RequestOptions.DEFAULT);
  9. esClient.close();
  10. System.out.println("update doc result: " + response.getGetResult());
  11. }
  • 删除文档 ```java public static void testDeleteDoc() throws IOException { RestHighLevelClient esClient = createClient();

    DeleteRequest deleteRequest = new DeleteRequest(); deleteRequest.index(“user”).id(“1001”);

    DeleteResponse response = esClient.delete(deleteRequest, RequestOptions.DEFAULT); esClient.close();

    System.out.println(“delete doc result: “ + response.getResult()); }

// 批量删除文档 public static void testBatchDeleteDoc() throws IOException { RestHighLevelClient esClient = createClient();

  1. BulkRequest bulkRequest = new BulkRequest();
  2. for (int i = 0; i < 5; i++) {
  3. DeleteRequest deleteRequest = new DeleteRequest();
  4. deleteRequest.index("user").id("100" + i);
  5. bulkRequest.add(deleteRequest);
  6. }
  7. BulkResponse response = esClient.bulk(bulkRequest, RequestOptions.DEFAULT);
  8. esClient.close();
  9. System.out.println(response.getTook());
  10. System.out.println(Arrays.toString(response.getItems()));

}

  1. - 根据id获取文档
  2. ```java
  3. public static void testGetDoc() throws IOException {
  4. RestHighLevelClient esClient = createClient();
  5. GetRequest getRequest = new GetRequest();
  6. getRequest.index("user").id("1006");
  7. GetResponse response = esClient.get(getRequest, RequestOptions.DEFAULT);
  8. esClient.close();
  9. System.out.println(response.getSource().toString());
  10. }
  • 查询索引中的全部数据

    1. public static void testQueryAll() throws IOException {
    2. RestHighLevelClient esClient = createClient();
    3. SearchRequest request = new SearchRequest();
    4. request.indices("user");
    5. request.source(new SearchSourceBuilder().query(QueryBuilders.matchAllQuery()));
    6. SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
    7. SearchHits hits = response.getHits();
    8. esClient.close();
    9. System.out.println(hits.getTotalHits());
    10. System.out.println(response.getTook());
    11. for (SearchHit hit : hits) {
    12. System.out.println(hit.getSourceAsString());
    13. }
    14. }
  • 条件查询 : termQuery

    1. public static void testQueryTerm() throws IOException {
    2. RestHighLevelClient esClient = createClient();
    3. SearchRequest request = new SearchRequest();
    4. request.indices("user");
    5. TermQueryBuilder termQuery = QueryBuilders.termQuery("age", "20");
    6. SearchSourceBuilder query = new SearchSourceBuilder().query(termQuery);
    7. request.source(query);
    8. SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
    9. esClient.close();
    10. SearchHits hits = response.getHits();
    11. System.out.println(hits.getTotalHits());
    12. System.out.println(response.getTook());
    13. for ( SearchHit hit : hits ) {
    14. System.out.println(hit.getSourceAsString());
    15. }
    16. }
  • 分页查询

    1. public static void testQueryPage() throws IOException {
    2. RestHighLevelClient esClient = createClient();
    3. SearchRequest request = new SearchRequest();
    4. request.indices("user");
    5. SearchSourceBuilder builder = new SearchSourceBuilder().query(QueryBuilders.matchAllQuery());
    6. // (当前页码 - 1) * 每页显示数据条数
    7. builder.from(0);
    8. // 每页显示数量
    9. builder.size(4);
    10. request.source(builder);
    11. SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
    12. esClient.close();
    13. SearchHits hits = response.getHits();
    14. System.out.println(hits.getTotalHits());
    15. System.out.println(response.getTook());
    16. for ( SearchHit hit : hits ) {
    17. System.out.println(hit.getSourceAsString());
    18. }
    19. }
  • 排序

    1. public static void testQueryOrderBy() throws IOException {
    2. RestHighLevelClient esClient = createClient();
    3. SearchRequest request = new SearchRequest();
    4. request.indices("user");
    5. SearchSourceBuilder builder = new SearchSourceBuilder().query(QueryBuilders.matchAllQuery());
    6. // 根据 age 反向排序
    7. builder.sort("age", SortOrder.DESC);
    8. request.source(builder);
    9. SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
    10. esClient.close();
    11. SearchHits hits = response.getHits();
    12. System.out.println(hits.getTotalHits());
    13. System.out.println(response.getTook());
    14. for ( SearchHit hit : hits ) {
    15. System.out.println(hit.getSourceAsString());
    16. }
    17. }
  • 只查询部分字段

    1. public static void testQuerySource() throws IOException {
    2. RestHighLevelClient esClient = createClient();
    3. SearchRequest request = new SearchRequest();
    4. request.indices("user");
    5. SearchSourceBuilder builder = new SearchSourceBuilder().query(QueryBuilders.matchAllQuery());
    6. // 声明不需要查询的字段
    7. String[] excludes = {"age"};
    8. // 声明需要查询的字段
    9. String[] includes = {};
    10. builder.fetchSource(includes, excludes);
    11. request.source(builder);
    12. SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
    13. esClient.close();
    14. SearchHits hits = response.getHits();
    15. System.out.println(hits.getTotalHits());
    16. System.out.println(response.getTook());
    17. for ( SearchHit hit : hits ) {
    18. System.out.println(hit.getSourceAsString());
    19. }
    20. }
  • 范围查询

    1. public static void testQueryScope() throws IOException {
    2. RestHighLevelClient esClient = createClient();
    3. SearchRequest request = new SearchRequest();
    4. request.indices("user");
    5. SearchSourceBuilder builder = new SearchSourceBuilder();
    6. RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("age");
    7. rangeQuery.gte(18);
    8. rangeQuery.lt(28);
    9. builder.query(rangeQuery);
    10. request.source(builder);
    11. SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
    12. SearchHits hits = response.getHits();
    13. System.out.println(hits.getTotalHits());
    14. System.out.println(response.getTook());
    15. for ( SearchHit hit : hits ) {
    16. System.out.println(hit.getSourceAsString());
    17. }
    18. }
  • 模糊查询

    1. public static void testQueryFuzzy() throws IOException {
    2. RestHighLevelClient esClient = createClient();
    3. SearchRequest request = new SearchRequest();
    4. request.indices("user");
    5. SearchSourceBuilder builder = new SearchSourceBuilder();
    6. builder.query(QueryBuilders.fuzzyQuery("name", "name:6")
    7. .fuzziness(Fuzziness.ZERO)); // Fuzziness.ZERO ONE TWO 代表相差n个字符
    8. request.source(builder);
    9. SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
    10. esClient.close();
    11. SearchHits hits = response.getHits();
    12. System.out.println(hits.getTotalHits());
    13. System.out.println(response.getTook());
    14. for ( SearchHit hit : hits ) {
    15. System.out.println(hit.getSourceAsString());
    16. }
    17. }
  • 高亮查询

    1. public static void testHighlightQuery() throws IOException {
    2. RestHighLevelClient esClient = createClient();
    3. SearchRequest request = new SearchRequest();
    4. request.indices("user");
    5. SearchSourceBuilder builder = new SearchSourceBuilder();
    6. TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery("name", "name");
    7. builder.query(termsQueryBuilder);
    8. HighlightBuilder highlightBuilder = new HighlightBuilder();
    9. highlightBuilder.preTags("<font color='red'>");
    10. highlightBuilder.postTags("</font>");
    11. highlightBuilder.field("name");
    12. builder.highlighter(highlightBuilder);
    13. request.source(builder);
    14. SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
    15. esClient.close();
    16. SearchHits hits = response.getHits();
    17. System.out.println(hits.getTotalHits());
    18. System.out.println(response.getTook());
    19. for ( SearchHit hit : hits ) {
    20. System.out.println(hit.getSourceAsString());
    21. // 高亮标签拼接在这里
    22. System.out.println(hit.getHighlightFields());
    23. }
    24. }
  • 聚合查询

    1. public static void testQueryAggregation() throws IOException {
    2. RestHighLevelClient esClient = createClient();
    3. SearchRequest request = new SearchRequest();
    4. request.indices("user");
    5. SearchSourceBuilder builder = new SearchSourceBuilder();
    6. // 查询age最大值
    7. AggregationBuilder aggregationBuilder = AggregationBuilders.max("maxAge").field("age");
    8. // 按照age分组,并返回每组的数量
    9. // AggregationBuilder aggregationBuilder = AggregationBuilders.terms("maxGroup").field("age");
    10. builder.aggregation(aggregationBuilder);
    11. request.source(builder);
    12. SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
    13. esClient.close();
    14. SearchHits hits = response.getHits();
    15. System.out.println(hits.getTotalHits());
    16. System.out.println(response.getTook());
    17. for ( SearchHit hit : hits ) {
    18. System.out.println(hit.getSourceAsString());
    19. }
    20. }
  • 复杂的查询

    1. /**
    2. * 测试查询数据
    3. */
    4. @Test
    5. public void searchData() throws IOException {
    6. // 创建查询对象
    7. SearchRequest searchRequest = new SearchRequest();
    8. // 指定索引
    9. searchRequest.indices("bank");
    10. // 封装检索条件
    11. SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    12. // 构造检索条件
    13. searchSourceBuilder.query(QueryBuilders.matchQuery("address", "mill"));
    14. TermsAggregationBuilder ageAgg = AggregationBuilders.terms("ageAgg").field("age").size(10);
    15. searchSourceBuilder.aggregation(ageAgg);
    16. AvgAggregationBuilder balanceAvg = AggregationBuilders.avg("balanceAvg").field("balance");
    17. searchSourceBuilder.aggregation(balanceAvg);
    18. // 将查询条件传给查询请求对象
    19. searchRequest.source(searchSourceBuilder);
    20. // 发起查询请求,返回结果
    21. SearchResponse searchResponse = client.search(searchRequest, GulimallElasticSearchConfig.COMMON_OPTIONS);
    22. // 获取聚集结果
    23. Aggregations aggregations = searchResponse.getAggregations();
    24. Terms ageAggRes = aggregations.get("ageAgg");
    25. for (Terms.Bucket bucket : ageAggRes.getBuckets()) {
    26. System.out.println(bucket.getKey() + " : " + bucket.getDocCount());
    27. }
    28. Avg balanceAvgRes = aggregations.get("balanceAvg");
    29. System.out.println("balanceAvg: " + balanceAvgRes.getValue());
    30. // 获取 _source 结果
    31. SearchHit[] hits = searchResponse.getHits().getHits();
    32. for (SearchHit hit : hits) {
    33. System.out.println("docId: " + hit.docId());
    34. System.out.println("id: " + hit.getId());
    35. Map<String, Object> sourceAsMap = hit.getSourceAsMap();
    36. System.out.println("firstname: " + sourceAsMap.get("firstname"));
    37. System.out.println("lastname: " + sourceAsMap.get("lastname"));
    38. System.out.println("---");
    39. }
    40. }