ElasticSearch 集成 SpringBoot

方法有这几种

1.9300:TCP

  • spring-data-elasticsearch:transport-api.jar
    • springboot 版本不同,transport-api.jar 不同,不能适配 es 版本
    • 7.x 已经不建议使用,8以上就要废弃
  1. 9200:HTTP
  • jestClient: 非官方,更新慢
  • RestTemplate:模拟发送HTTP请求,ES很多操作都要自己封装
  • HttpClient:同上
  • ElasticSearch-Rest-Client: 官方 RestClient,封装了 ES 操作,API层次分明,上手简单

官方文档

ElasticSearch 集成 SpringBoot

ElasticSearch 集成 SpringBoot

ElasticSearch 集成 SpringBoot

1、找到原生的依赖

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.9.2</version>
</dependency>

2、找对象

ElasticSearch 集成 SpringBoot
3、分析这个类中的方法

配置基本的项目

ElasticSearch 集成 SpringBoot
问题:一定要保证我们导入的依赖和我们使用的一致

ElasticSearch 集成 SpringBoot
相关源码

ElasticSearch 集成 SpringBoot

具体的API测试

1、创建索引
2、判断索引是否存在
3、删除索引
4、创建文档
5、CRUD文档

配置文件

@Configuration
public class ElasticSearchClientConfig {

    // spring <beans id="restHighLevelClient" class="RestHighLevelClient">
    @Bean
    public RestHighLevelClient restHighLevelClient() {
        RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(new HttpHost("127.0.0.1", 9200,"http")));
        return client;
    }
}
@SpringBootTest
class HuduEsApiApplicationTests {

    //面向对象来操作
    @Autowired
    @Qualifier("restHighLevelClient")
    private RestHighLevelClient client;

    // 测试索引的创建 Request请求 PUT hudu_index
    @Test
    void testCreateIndex() throws IOException {
        //1、创建索引请求
        CreateIndexRequest request = new CreateIndexRequest("hudu_index");
        //2、客户端执行创建请求
        CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);
        System.out.println(createIndexResponse);
    }

    //测试获取索引,只能判断其是否存在
    @Test
    void testExistIndex() throws IOException {
        GetIndexRequest request = new GetIndexRequest("hudu_index");
        boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
        System.out.println(exists);
    }


    //测试删除索引
    @Test
    void deleteIndex() throws IOException {
        DeleteIndexRequest request = new DeleteIndexRequest("hudu_index");
        //删除
        AcknowledgedResponse delete = client.indices().delete(request, RequestOptions.DEFAULT);
        System.out.println(delete.isAcknowledged());
    }

    //测试添加文档
    @Test
    void testAddDocument() throws IOException {
        //创建对象
        User user = new User("hudu", 3);
        //创建请求
        IndexRequest request = new IndexRequest("hudu_index");

        //规则 PUT /hudu_index/_doc/1
        request.id("1");
        request.timeout(TimeValue.timeValueSeconds(1));
        request.timeout("1s");

        //将我们的数据放入请求
        request.source(JSON.toJSONString(user), XContentType.JSON);

        //客户端发送请求,获取响应结果
        IndexResponse indexResponse = client.index(request, RequestOptions.DEFAULT);

        System.out.println(indexResponse.toString());//
        System.out.println(indexResponse.status());//对应命令行的状态

    }

    //获取文档,判断是否存在 get /index/_doc/1
    @Test
    void testIsExists() throws IOException {
        GetRequest getRequest = new GetRequest("hudu_index", "1");
        //不获取返回的_source 的上下文
        getRequest.fetchSourceContext(new FetchSourceContext(false));
        getRequest.storedFields("_none_");

        boolean exists = client.exists(getRequest, RequestOptions.DEFAULT);
        System.out.println(exists);
    }

    //获得文档的信息
    @Test
    void testGetDocument() throws IOException {
        GetRequest getRequest = new GetRequest("hudu_index", "1");
        GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT);
        System.out.println(getResponse.getSourceAsString());//打印文档的内容
        System.out.println(getResponse);//返回的全部内容和命令是一样的

    }

    //更新文档信息
    @Test
    void testUpdateDocument() throws IOException {
        UpdateRequest updateRequest = new UpdateRequest("hudu_index", "1");
        updateRequest.timeout("1s");

        User user = new User("Alex", 20);
        updateRequest.doc(JSON.toJSONString(user),XContentType.JSON);

        UpdateResponse updateResponse = client.update(updateRequest, RequestOptions.DEFAULT);
        System.out.println(updateResponse.status());
    }

    //删除文档记录
    @Test
    void testDeleteRequest() throws IOException {
        DeleteRequest deleteRequest = new DeleteRequest("hudu_index","3");
        deleteRequest.timeout("1s");

        DeleteResponse deleteResponse = client.delete(deleteRequest, RequestOptions.DEFAULT);
        System.out.println(deleteResponse.status());
    }

    //特殊的,真实的项目一般都会批量插入数据!
    @Test
    void testBulkRequest() throws IOException {
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout("10s");

        ArrayList<User> userList = new ArrayList<>();
        userList.add(new User("hudu1",20));
        userList.add(new User("hudu2",21));
        userList.add(new User("hudu3",22));
        userList.add(new User("hudu4",23));
        userList.add(new User("hudu5",24));

        //批处理请求
        for (int i = 0; i < userList.size(); i++) {
            //批量更新和批量删除,就在这里修改对应的请求即可
            bulkRequest.add(
                    new IndexRequest("hudu_index")
                    .id(""+(i+1))
                    .source(JSON.toJSONString(userList.get(i)),XContentType.JSON)
            );

            BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);
            System.out.println(bulkResponse.hasFailures());//是否失败,返回false表示成功
        }

    }

    //查询
    //SearchRequest搜索请求
    //SearchSourceBuilder 条件构造
    //HighlightBuilder 构建高亮
    //termQueryBuilder 构建精确查询
    // MatchAllQueryBuilder
    // xxxQueryBuilder 对应我们刚才看到的命令
    @Test
    void testSearch() throws IOException {
        SearchRequest searchRequest = new SearchRequest("hudu_index");
        //构建搜索条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        //查询条件,我们可以使用QueryBuilders 工具类来实现
        //QueryBuilders.termQuery 精确匹配
        //QueryBuilders.matchAllQuery() 匹配所有
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", "hudu1");
//        MatchAllQueryBuilder queryBuilder = QueryBuilders.matchAllQuery();
        sourceBuilder.query(termQueryBuilder);
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));

        searchRequest.source(sourceBuilder);

        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        System.out.println(searchResponse.getHits());
        System.out.println("=====================================");
        for (SearchHit documentFields : searchResponse.getHits().getHits()) {
            System.out.println(documentFields.getSourceAsMap());
        }
    }
}

通过 SpringData 整合

添加依赖

springData 官方文档

ElasticSearch 集成 SpringBoot

根据自己的需求来选择需要的版本

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

常用注解

// 标识映射到 Elasticsearch 文档上的领域对象
public @interface Document {
    // 索引名称,mysql中数据库概念
    String indexName();
    // 文档类型,mysql 中表的概念
    String type() defalut "";
    // 默认分片数
    short shards() defalut 5;
    // 默认副本数量
    short replicas() default 1;
}
// 表示是文档的id,文档可以认为mysql主键概念
public @interface Field {
    // 文档字段的类型
    FieldType type() defalut FieldType.Auto;
    // 是否建立倒排索引
    boolean index() defalut true;
    // 是否进行存储
    boolean storeI() defalut false;
    // 分词器名称
    String analyzer() default "";
}
// 为文档自动指定元数据类型
public enum FieldType {
    Text, // 会进行分词并建立索引的字符串类型
    Integer,
    Long,
    Date,
    Float,
    Double,
    Boolean,
    Object,
    Auto, // 自动判断字段类型
    Nested, // 嵌套对象类型
    Ip,
    Attachment,
    Keyword // 不会进行分词建立索引
}

写配置

# es 配置
# es reposity配置
elasticsearch:
  rest:
  uris: http://192.168.33.61:9200
# template
data:
  elasticsearch:
  repositories:
  enabled: true
  client:
  reactive:
  endpoints: 192.168.33.61:9200

ElasticsearchRepository

关键字 使用示例 等同于 ES 查询
And findByNameAndPrice “bool”: {“must”: [{“field”: {“name”:”?”}},{“field”: {“price”:”?”}}]}
Or findByNameOrPrice “bool”: {“should”: [{“field”: {“name”:”?”}},{“field”: {“price”:”?”}}]}
Is findByName “bool”: {“must”: [{“field”:{“name”:”?”}}]}
Not findByNameNot “bool”: {“must_not”: [{“field”:{“name”:”?”}}]}

ElasticSearch 集成 SpringBoot

ElasticSearch 集成 SpringBoot

整合应用

引入依赖

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

配置客户端

@Configuration
public class RestClientConfig extends AbstractElasticsearchConfiguration {
    @Override
    public RestHighLevelClient elasticsearchClient() {
        final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
                .connectedTo("localhost:9200")
                .build();
        return RestClients.create(clientConfiguration).rest();
    }
}

客户端对象

  • ElasticsearchOperations
  • RestHighLevelClient 推荐

ElasticsearchOperations

  • 特点:始终使用面向对象的方式操作 ES
    • 索引:用来存放相似文档集合
    • 映射:用来决定放入文档中的每个字段以什么样的方式存入 ES 中,例如字段类型、分词器。。。
    • 文档:可以被索引的最小单元 json 数据格式
相关注解
// 用在类上 indexName 索引名称,createIndex 是否创建索引
@Document(indexName = "products", createIndex = true)
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Product {
    // 用在属性上 将对象 id 字段与 ES 中文档的 _id 对应
    @Id
    private Integer id;
    // 用在属性上,用来描述属性在 ES 中存储类型以及分词情况
    @Field(type = FieldType.Keyword)
    private String title;
    @Field(type = FieldType.Double)
    private Double price;
    @Field(type = FieldType.Text,analyzer = "ik_max_word")
    private String description;
    @Field(type = FieldType.Date,format = {},pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createdAt;
}

索引文档

@Test
public void testCreate() {
    Product product = new Product();
    product.setId(1); // 存在id指定id,不存在id自动生成id
    product.setTitle("面包");
    product.setPrice(15.5);
    product.setDescription("面包真好吃");
    product.setCreatedAt(LocalDateTime.now());
    elasticsearchOperations.save(product);
}

查询文档

@Test
public void testSearch() {
    Product product = elasticsearchOperations.get("1", Product.class);
    System.out.println(product);
}

删除文档

@Test
public void testDelete() {
    Product product = new Product();
    product.setId(1);
    String delete = elasticsearchOperations.delete(product);
    System.out.println(delete);
}

删除所有

@Test
public void testDeleteAll() {
    ByQueryResponse delete = elasticsearchOperations.delete(Query.findAll(), Product.class);
    System.out.println(delete.getDeleted());
}

查询所有

@Test
public void testFindAll() {
    SearchHits<Product> productSearchHits = elasticsearchOperations.search(Query.findAll(), Product.class);
    productSearchHits.forEach(productSearchHit -> {
        System.out.println("id:" + productSearchHit.getId());
        System.out.println("score:" + productSearchHit.getScore());
        System.out.println("product:" + productSearchHit.getContent());
    });
}

RestHighLevelClient

创建索引和映射

@Test
    public void indexTest() throws IOException {
        CreateIndexRequest createIndexRequest = new CreateIndexRequest("products");
        //指定映射
        // 参数 1:指定映射 json 结构,参数 2:指定数据类型
        createIndexRequest.mapping("{\n" +
                "    \"properties\": {\n" +
                "      \"id\":{\n" +
                "        \"type\": \"integer\"\n" +
                "      },\n" +
                "      \"title\":{\n" +
                "        \"type\": \"keyword\"\n" +
                "      },\n" +
                "      \"price\":{\n" +
                "        \"type\": \"double\"\n" +
                "      },\n" +
                "      \"created_at\":{\n" +
                "        \"type\": \"text\"\n" +
                "      },\n" +
                "      \"description\":{\n" +
                "        \"type\": \"text\",\n" +
                "        \"analyzer\": \"ik_max_word\"\n" +
                "      }\n" +
                "    }\n" +
                "  }", XContentType.JSON);
        // 参数 1:创建索引的请求对象 参数 2:请求配置对象
        CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
        System.out.println("创建状态:"+createIndexResponse.isAcknowledged());
        restHighLevelClient.close(); // 关闭资源
    }

对比 kibana 创建索引语句

PUT /products
{
  "mappings": {
    "properties": {
      "id":{
        "type": "integer"
      },
      "title":{
        "type": "keyword"
      },
      "price":{
        "type": "double"
      },
      "created_at":{
        "type": "text"
      },
      "description":{
        "type": "text",
        "analyzer": "ik_max_word"
      }
    }
  }
}

删除索引

@Test
public void testDeleteIndex() throws IOException {
    DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest("products");
    // 参数 1:删除索引对象,参数 2:请求配置
    AcknowledgedResponse response = restHighLevelClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
    System.out.println(response.isAcknowledged());
}

对比 kibana

DELETE /products

索引文档

@Test
    public void testCreate() throws IOException {
        // 参数 1:索引请求对象,2:请求配置对象
        IndexRequest indexRequest = new IndexRequest("products");
        indexRequest.id("1") // 手动指定文档 id
                .source("{\n" +
                "  \"id\":1,\n" +
                "  \"title\":\"iphone 13\",\n" +
                "  \"price\":5599.99,\n" +
                "  \"created_at\":\"2022-05-17\",\n" +
                "  \"description\":\"iphone 14 屏幕采用 6.1 英寸 OLED 屏幕\"\n" +
                "}", XContentType.JSON); // 指定文档数据
        IndexResponse response = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
        System.out.println(response.status());
    }

对比 kibana

POST /products/_doc/1
{
  "id":1,
  "title":"iphone 14",
  "price":5599.99,
  "created_at":"2022-05-17",
  "description":"iphone 14 屏幕采用 6.2 英寸 OLED 屏幕"
}

更新文档

@Test
    public void testUpdate() throws IOException {
        UpdateRequest updateRequest = new UpdateRequest("products","1");
        updateRequest.doc("{\n" +
                "    \"title\":\"iphone 12\"\n" +
                "  }",XContentType.JSON);
        UpdateResponse updateResponse = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
        System.out.println(updateResponse.status());
    }

批量更新

@Test
public void updateByQuery() {
        String[] ids = new String[]{"2","3"};
        try {
            UpdateByQueryRequest updateByQueryRequest = new UpdateByQueryRequest("products");
            HashMap<String, Object> map = new HashMap<>();
            // 需要修改的数据
            map.put("price",1);
            // 需要执行的脚本
            String code = "ctx._source.isEncrypt=params.price";
            updateByQueryRequest
                    .setScript(new Script(Script.DEFAULT_SCRIPT_TYPE,Script.DEFAULT_SCRIPT_LANG,code,map))
                    .setQuery(QueryBuilders.idsQuery().addIds(ids));
            System.out.println(updateByQueryRequest.toString());
            restHighLevelClient.updateByQuery(updateByQueryRequest,RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

对比 kibana

将所有的牛奶价格都更新为 59。

POST /products/_update_by_query
{
  "script": {
    "source": "ctx._source.price=59",
    "lang": "painless"
  }, 
  "query": {
    "ids": {
      "values": [2,3]
    }
  }
}

对比 kibana

POST /products/_doc/1/_update
{
  "doc":{
    "title":"iphone 12"
  }
}

删除文档

@Test
    public void testDelete() throws IOException {
        DeleteResponse deleteResponse = restHighLevelClient.delete(new DeleteRequest("products", "1"), RequestOptions.DEFAULT);
        System.out.println(deleteResponse.status());
    }

对比 kibana

DELETE /product/_doc/1

基于 id 查询文档

@Test
    public void testGet() throws IOException {
        GetResponse getResponse = restHighLevelClient.get(new GetRequest("products", "1"), RequestOptions.DEFAULT);
        System.out.println(getResponse.getSourceAsString());
    }

对比 kibana

GET /products/_doc/1

查询所有

@Test
    public void testMatchAll() throws IOException {
        // 指定查询索引
        SearchRequest searchRequest = new SearchRequest("products");
        // 指定条件对象
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 查询所有
        sourceBuilder.query(QueryBuilders.matchAllQuery());
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        System.out.println("总条数" + searchResponse.getHits().getTotalHits().value);
        System.out.println("最大得分" + searchResponse.getHits().getMaxScore());
        // 获取结果
        SearchHit[] hits = searchResponse.getHits().getHits();
        for (SearchHit hit : hits) {
            String id = hit.getId();
            System.out.println("id" + id + "source:" + hit.getSourceAsString());
        }
    }

对比 kibana

GET /products/_search
{
  "query": {
    "match_all": {}
  }
}

文档查询

@Test
    public void testTermSearch() throws IOException {
        // 1. term 查询
        query(QueryBuilders.termQuery("description","iphone"));
        // 2. range 查询
        query(QueryBuilders.rangeQuery("price").gte(100).lte(9000));
        // 3. prefix 前缀查询
        query(QueryBuilders.prefixQuery("title","iphone"));
        // 4. wildcard 通配符
        query(QueryBuilders.wildcardQuery("title","iph*"));
        // 5. ids 指定多个id
        query(QueryBuilders.idsQuery().addIds("1"));
        // 6. multi_match 多字段查询
        query(QueryBuilders.multiMatchQuery("屏幕","description","title"));
    }

    public void query(QueryBuilder queryBuilder) throws IOException {
        SearchRequest searchRequest = new SearchRequest("products");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 指定查询条件
        sourceBuilder.query(queryBuilder);
        searchRequest.source(sourceBuilder);

        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        System.out.println("总条数" + searchResponse.getHits().getTotalHits().value);
        System.out.println("最大得分" + searchResponse.getHits().getMaxScore());
        for (SearchHit hit : searchResponse.getHits().getHits()) {
            System.out.println(hit.getSourceAsString());
        }
    }
@Test
    public void testSearch() throws IOException {
        SearchRequest searchRequest = new SearchRequest("products");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 创建高亮匹配
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.requireFieldMatch(false)
                .field("description").field("title")
                .preTags("<front style='color:red'>")
                .postTags("</front>");
        sourceBuilder.query(QueryBuilders.matchQuery("description","iphone"))
                .from(0) // 起始位置 start = (page-1) * size
                .size(10) // 每页显示条数,默认返回 10 条
                .sort("price", SortOrder.ASC) // 排序
                // .fetchSource(new String[]{"id","title"},new String[]{}); // 参数 1:包含字段数组 2:排除字段数组
                .highlighter(highlightBuilder); // 高亮搜索
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        System.out.println("总条数" + searchResponse.getHits().getTotalHits().value);
        System.out.println("最大得分" + searchResponse.getHits().getMaxScore());
        for (SearchHit hit : searchResponse.getHits().getHits()) {
            System.out.println(hit.getSourceAsString());
            // 获取高亮字段
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            if (highlightFields.containsKey("description")) {
                System.out.println(highlightFields.get("description").getFragments()[0]);
            }
            if (highlightFields.containsKey("title")) {
                System.out.println(highlightFields.get("title").getFragments()[0]);
            }
        }
    }

对比 kibana

GET /products/_search
{
  "query": {
    "match": {
      "description": "iphone"
    }
  },
  "from": 0,
  "size": 10,
  "sort": [
    {
      "price": {
        "order": "asc"
      }
    }
  ], 
  "_source": ["id","title"],
  "highlight": {
    "require_field_match": "false", 
    "pre_tags": ["<span stype='color:red'>"],
    "post_tags": ["</span>"], 
    "fields": {"description": {},"title":{}}
  }
}

过滤查询

@Test
    public void testFilterQuery() throws IOException {
        SearchRequest searchRequest = new SearchRequest("products");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(QueryBuilders.matchAllQuery())
                .postFilter(QueryBuilders.rangeQuery("price").gte(10).lte(6000)); // 用来指定过滤条件
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        System.out.println("总条数" + searchResponse.getHits().getTotalHits().value);
        System.out.println("最大得分" + searchResponse.getHits().getMaxScore());
        for (SearchHit hit : searchResponse.getHits().getHits()) {
            System.out.println(hit.getSourceAsString());
        }
    }

对比 kibana

GET /products/_search
{
  "query": {
    "match_all": {}
  },
  "post_filter": {
    "range": {
      "price": {
        "gte": 10,
        "lte": 6000
      }
    }
  }
}

实际开发应用

/**
     * 将对象放入 ES 中
     */
    @Test
    public void testIndex() throws IOException {
        Product product = new Product();
        product.setId(2);
        product.setTitle("小浣熊干吃面");
        product.setPrice(1.5);
        product.setDescription("小浣熊干吃面真好吃!");
        product.setCreatedAt(LocalDateTime.now());

        IndexRequest indexRequest = new IndexRequest("products");
        indexRequest.id(product.getId().toString())
                .source(new ObjectMapper().registerModule(new JavaTimeModule()).writeValueAsString(product), XContentType.JSON);
        IndexResponse indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
        System.out.println(indexResponse.status());
    }

    /**
     * 查询数据
     */
    @Test
    public void testSearch() throws IOException {
        SearchRequest searchRequest = new SearchRequest("products");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.requireFieldMatch(false).field("title").preTags("<span style='color:red'>").postTags("<span>");
        sourceBuilder.query(QueryBuilders.prefixQuery("title","小浣熊"))
                .from(0)
                .size(10)
                .highlighter(highlightBuilder);
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        List<Product> products = new ArrayList<>();
        for (SearchHit hit : searchResponse.getHits().getHits()) {
            System.out.println(hit.getSourceAsString());
            Product product = new ObjectMapper().registerModule(new JavaTimeModule()).readValue(hit.getSourceAsString(), Product.class);
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            if (highlightFields.containsKey("title")) {
                product.setTitle(highlightFields.get("title").getFragments()[0].toString());
            }
            products.add(product);
        }

        products.forEach(System.out::println);
    }

聚合查询

索引以及数据准备

PUT /products
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 0
  }, 
  "mappings": {
    "properties": {
      "id":{
        "type": "integer"
      },
      "category":{
        "type": "keyword"
      },
      "title":{
        "type": "text"
      },
      "price":{
        "type": "double"
      },
      "created_at":{
        "type": "date"
      },
      "description":{
        "type": "text",
        "analyzer": "ik_max_word"
      }
    }
  }
}

PUT /products/_bulk
{"index":{"_id":1}}
{"id":1,"category":"零食","title":"薯片","price":8.9,"created_at":"2022-05-21","description":"薯片真好吃"}
{"index":{"_id":2}}
{"id":2,"category":"零食","title":"糖","price":4.5,"created_at":"2022-05-21","description":"糖真甜"}
{"index":{"_id":3}}
{"id":3,"category":"饮料","title":"可乐","price":7.0,"created_at":"2022-05-21","description":"2L 可乐"}
{"index":{"_id":4}}
{"id":4,"category":"饮料","title":"椰汁","price":15.0,"created_at":"2022-05-21","description":"1.5L 椰汁"}
{"index":{"_id":5}}
{"id":5,"category":"生活用品","title":"抽纸","price":9.9,"created_at":"2022-05-21","description":"三连包抽纸"}
{"index":{"_id":6}}
{"id":6,"category":"生活用品","title":"电动牙刷","price":199.9,"created_at":"2022-05-21","description":"米家电动牙刷"}
{"index":{"_id":7}}
{"id":7,"category":"生活用品","title":"剃须刀","price":22.5,"created_at":"2022-05-21","description":"手动剃须刀"}

根据字段进行分组查询

GET /products/_search
{
  "query": {
    "match_all": {}
  },
  "aggs": {
    "price_group": {
      "terms": {
        "field": "price"
      }
    }
  }
}
public void testGroupAgg() throws IOException {
        SearchRequest searchRequest = new SearchRequest();
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(QueryBuilders.matchAllQuery()) // 查询条件
                .aggregation(AggregationBuilders.terms("price_group").field("price")) // 用来设置聚合处理
                .size(0);
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        Aggregations aggregations = searchResponse.getAggregations();
        ParsedDoubleTerms parsedDoubleTerms = aggregations.get("price_group");
        for (Terms.Bucket bucket : parsedDoubleTerms.getBuckets()) {
            System.out.println(bucket.getKey() + " " + bucket.getDocCount());
        }
    }
GET /products/_search
{
  "query": {
    "match_all": {}
  },
  "size": 0, 
  "aggs": {
    "price_sum": {
      "sum": {
        "field": "price"
      }
    }
  }
}
/**
     * max(ParsedMax) min(ParsedMin) sum(ParsedSum) avg(ParsedAvg) 聚合函数,桶中只有一个值
     */
    @Test
    public void testAggFunction() throws IOException {
        SearchRequest searchRequest = new SearchRequest();
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(QueryBuilders.matchAllQuery()) // 查询条件
                .aggregation(AggregationBuilders.sum("sum_price").field("price")) // 用来设置聚合处理
                .size(0);
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        Aggregations aggregations = searchResponse.getAggregations();
        ParsedSum parsedSum = aggregations.get("sum_price");
        System.out.println(parsedSum.getValue());
    }
本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
未填写
文章
247
粉丝
18
喜欢
217
收藏
62
排名:731
访问:9753
私信
所有博文
社区赞助商