elasticsearch(es)高级查询api

时间:2023-04-07 07:22:48

yml配置

  #es配置
spring:
  elasticsearch:
    rest:
      uris: 192.168.16.188:9200

添加依赖

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

使用编程的形式设置连接的ES服务器,并获取客户端对象,配置ES服务器地址与端口9200,记得客户端使用完毕需要手工关闭。由于当前客户端是手工维护的,因此不能通过自动装配的形式加载对象

@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringBootTest.class)
public class JeecgTest {
    @Test
//    @SneakyThrows
    public void name() {

        HttpHost host = HttpHost.create("http://localhost:9200");
        RestClientBuilder builder = RestClient.builder(host);

        client = new RestHighLevelClient(builder);

        try {
            client.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
   }
}

使用客户端对象操作ES,例如创建索引

@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringBootTest.class)
public class JeecgTest {
    private RestHighLevelClient client;
      @Test
      void testCreateIndex() throws IOException {
          HttpHost host = HttpHost.create("http://localhost:9200");
          RestClientBuilder builder = RestClient.builder(host);
          client = new RestHighLevelClient(builder);
        
          CreateIndexRequest request = new CreateIndexRequest("books");
          client.indices().create(request, RequestOptions.DEFAULT); 
        
          client.close();
      }
}

添加文档,添加文档使用的请求对象是IndexRequest,与创建索引使用的请求对象不同

@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringBootTest.class)
public class JeecgTest {
    @Test
    public void testCreateIndex() throws IOException {
        HttpHost host = HttpHost.create("http://192.168.16.188:9200");
        RestClientBuilder builder = RestClient.builder(host);
        client = new RestHighLevelClient(builder);
        HashMap<String, Object> map = new HashMap<>();
        map.put("name", "张三");
        map.put("age", 20);
        IndexRequest request = new IndexRequest("user");
        String json = JSON.toJSONString(map);
        request.source(json, XContentType.JSON);
        IndexResponse index = client.index(request, RequestOptions.DEFAULT);
        client.close();
    }
}

/增量更新文档

  @Test
  public void testUpdateDoc() throws IOException {
      HttpHost host = HttpHost.create("http://192.168.16.188:9200");
      RestClientBuilder builder = RestClient.builder(host);
      client = new RestHighLevelClient(builder);
      UpdateRequest updateRequest = new UpdateRequest("user", "88");
      updateRequest.timeout("1s");
      User user = new User();
      user.setAge(222);
      updateRequest.doc(JSON.toJSONString(user), XContentType.JSON);
      UpdateResponse update = client.update(updateRequest, RequestOptions.DEFAULT);
      client.close();
  }

批量添加文档:批量做时,先创建一个BulkRequest的对象,可以将该对象理解为是一个保存request对象的容器,将所有的请求都初始化好后,添加到BulkRequest对象中,再使用BulkRequest对象的bulk方法,一次性执行完毕

    @Test
    //批量添加文档
    public void testCreateDocAll() throws IOException {
        HttpHost host = HttpHost.create("http://192.168.16.188:9200");
        RestClientBuilder builder = RestClient.builder(host);
        client = new RestHighLevelClient(builder);
        List<Map> list = new ArrayList<>();
        HashMap<String, Object> map = new HashMap<>();
        for (int i = 0; i < 3; i++) {
            map.put("aa" + i, i);
            list.add(map);
        }
        BulkRequest bulk = new BulkRequest();
        for (Map map1 : list) {
            IndexRequest request = new IndexRequest("user");
            String json = JSON.toJSONString(map1);
            request.source(json, XContentType.JSON);
            bulk.add(request);
        }
        client.bulk(bulk, RequestOptions.DEFAULT);
        client.close();
    }

按id查询1文档:根据id查询文档使用的请求对象是GetRequest

    @Test
    //按id查询
    public void getById() throws IOException {
        HttpHost host = HttpHost.create("http://192.168.16.188:9200");
        RestClientBuilder builder = RestClient.builder(host);
        client = new RestHighLevelClient(builder);
        GetRequest request = new GetRequest("user", "88");
        GetResponse response = client.get(request, RequestOptions.DEFAULT);
        String json = response.getSourceAsString();
        System.out.println(json);
        client.close();
    }

通过id查询2

    @Test
    //按id查询
    public void getById2() throws IOException {
        HttpHost host = HttpHost.create("http://192.168.16.188:9200");
        RestClientBuilder builder = RestClient.builder(host);
        client = new RestHighLevelClient(builder);
        SearchRequest request = new SearchRequest("user");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.termQuery("_id",88));
        request.source(searchSourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        for (SearchHit hit : hits) {
            String source = hit.getSourceAsString();
            System.out.println(source);
        }
        client.close();
    }

按条件查询文档:按条件查询文档使用的请求对象是SearchRequest,查询时调用SearchRequest对象的termQuery方法,需要给出查询属性名,此处支持使用合并字段,也就是前面定义索引属性时添加的all属性

    @Test
    //按条件查询
    public void getBySearch() throws IOException {
        HttpHost host = HttpHost.create("http://192.168.16.188:9200");
        RestClientBuilder builder = RestClient.builder(host);
        client = new RestHighLevelClient(builder);
        SearchRequest request = new SearchRequest("user");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.matchPhraseQuery("name","张三"));
        request.source(searchSourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        for (SearchHit hit : hits) {
            String source = hit.getSourceAsString();
            System.out.println(source);
        }
        client.close();
    }

按条件高亮查询

    @Test
    //按条件高亮查询
    public void getBySearch2() throws IOException {
        HttpHost host = HttpHost.create("http://192.168.16.188:9200");
        RestClientBuilder builder = RestClient.builder(host);
        client = new RestHighLevelClient(builder);
        SearchRequest request = new SearchRequest("user");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.matchPhraseQuery("name","张三"));
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        searchSourceBuilder.highlighter(highlightBuilder.field("name"));
        request.source(searchSourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        for (SearchHit hit : hits) {
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            System.out.println(highlightFields);
        }
        client.close();
    }

全文高亮查询

    @Test
    //全文高亮查询
    public void getBySearch2() throws IOException {
        HttpHost host = HttpHost.create("http://192.168.16.188:9200");
        RestClientBuilder builder = RestClient.builder(host);
        client = new RestHighLevelClient(builder);
        SearchRequest request = new SearchRequest("user");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.multiMatchQuery("张三"));
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        searchSourceBuilder.highlighter(highlightBuilder.field("*"));
        request.source(searchSourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        for (SearchHit hit : hits) {
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            System.out.println(highlightFields);
        }
        client.close();
    }

分页查询

    @Test
    //分页查询
    public void getBySearch3() throws IOException {
        // 开始查询的记录数
        //页码
        Integer pageNum=1;
        //页数
        Integer pageSize=2;
        int start = (pageNum - 1) * pageSize;
        HttpHost host = HttpHost.create("http://192.168.16.188:9200");
        RestClientBuilder builder = RestClient.builder(host);
        client = new RestHighLevelClient(builder);
        SearchRequest request = new SearchRequest("user");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.matchAllQuery());
        searchSourceBuilder.from(start);
        searchSourceBuilder.size(pageSize);
        request.source(searchSourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        for (SearchHit hit : hits) {
            String sourceAsString = hit.getSourceAsString();
            System.out.println(sourceAsString);
        }
        client.close();
    }

MultiQuery 全部字段联合搜索

    @Test
    // MultiQuery 全部字段联合搜索 
    public void getBySearch4() throws IOException {
        HttpHost host = HttpHost.create("http://192.168.16.188:9200");
        RestClientBuilder builder = RestClient.builder(host);
        client = new RestHighLevelClient(builder);
        SearchRequest request = new SearchRequest("user");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.multiMatchQuery("三"));
        request.source(searchSourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        for (SearchHit hit : hits) {
            String source = hit.getSourceAsString();
            System.out.println(source);
        }
        client.close();
    }

MultiQuery 多字段联合搜索 ,使用多字段查询的时候,查询的字段要和查询的内容类型一直,不然就会报错,类似age字段是int类型,和name字段是string类型查询就会报错

    @Test
    // MultiQuery 多字段联合搜索
    public void getBySearch5() throws IOException {
        HttpHost host = HttpHost.create("http://192.168.16.188:9200");
        RestClientBuilder builder = RestClient.builder(host);
        client = new RestHighLevelClient(builder);
        SearchRequest request = new SearchRequest("user");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.multiMatchQuery("王","name","file"));
        request.source(searchSourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        for (SearchHit hit : hits) {
            String source = hit.getSourceAsString();
            System.out.println(source);
        }
        client.close();
    }

多域联合查询的时候,可以通过 boost 来设置某个域在计算得分时候的比重,比重越高的域当他符合条件时计算的得分越高,相应的该记录也更靠前。通过在 fields 中给相应的字段用 ^权重倍数来实现

	@Test
    // MultiQuery 多字段联合搜索和设置权重
    public void getBySearch6() throws IOException {
        HttpHost host = HttpHost.create("http://192.168.16.188:9200");
        RestClientBuilder builder = RestClient.builder(host);
        client = new RestHighLevelClient(builder);
        SearchRequest request = new SearchRequest("user");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.multiMatchQuery("广","name","address").field("name",10));
        request.source(searchSourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        for (SearchHit hit : hits) {
            String source = hit.getSourceAsString();
            System.out.println(source);
        }
        client.close();
    }

如果我们既要对一些字段进行分词查询,同时要对另一些字段进行精确查询,就需要使用布尔查询来实现了。布尔查询对应于Lucene的BooleanQuery查询,实现将多个查询组合起来,有三个可选的参数:must:文档必须匹配must所包括的查询条件,相当于 “AND”should:文档应该匹配should所包括的查询条件其中的一个或多个,相当于 "OR"must_not:文档不能匹配must_not所包括的该查询条件,相当于“NOT”

```erlang
GET user/_search
{
    "query": {
        "bool": { // 布尔查询
            "must": [ // 查询条件 must 表示数组中的查询方式所规定的条件都必须满足
                {
                    "multi_match": {
                        "query": "王小妹",
                        "minimum_should_match": "50%",
                        "fields": [
                            "name^10",
                            "title"
                        ]
                    }
                },
                {
                    "match": {
                        "address": "广州"
                    }
                }
            ]
        }
    }
}
    @Test
    // 布尔查询 BoolQuery
    public void getBySearch7() throws IOException {
        HttpHost host = HttpHost.create("http://192.168.16.188:9200");
        RestClientBuilder builder = RestClient.builder(host);
        client = new RestHighLevelClient(builder);
        SearchRequest request = new SearchRequest("user");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 搜索方式
        // 首先构造多关键字查询条件
        MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("王小妹", "name", "title").field("name", 10);
        // 然后构造匹配查询条件
        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("address", "广州");
        // 组合两个条件,组合方式为 must 全满足
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(multiMatchQueryBuilder);
        boolQueryBuilder.must(matchQueryBuilder);
        // 将查询条件封装给查询对象
        searchSourceBuilder.query(boolQueryBuilder);
        request.source(searchSourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        for (SearchHit hit : hits) {
            String source = hit.getSourceAsString();
            System.out.println(source);
        }
        client.close();
    }

定义过滤器查询,是在原本查询结果的基础上对数据进行筛选,因此省略了重新计算的分的步骤,效率更高。并且方便缓存。推荐尽量使用过虑器去实现查询或者过虑器和查询共同使用,过滤器在布尔查询中使用,下边是在搜索结果的基础上进行过滤:

GET user/_search
{
    "query": {
        "bool": {
            "must": [
                {
                    "multi_match": {
                        "query": "王小妹",
                        "minimum_should_match": "50%",
                        "fields": [
                            "name^10",
                            "title"
                        ]
                    }
                }
            ],
            "filter": [
                {
                    // 过滤条件:studymodel 必须是 201001
                    "match": {"address": "广州"}
                },
                {
                    // 过滤条件:年龄 >=10 <=100
                    "range": {"age": {"gte": 10,"lte": 100}}
                }
            ]
        }
    }
}
    @Test
    // 过滤器
    public void getBySearch8() throws IOException {
        HttpHost host = HttpHost.create("http://192.168.16.188:9200");
        RestClientBuilder builder = RestClient.builder(host);
        client = new RestHighLevelClient(builder);
        SearchRequest request = new SearchRequest("user");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 搜索方式
        // 首先构造多关键字查询条件
        MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("王小妹", "name", "title").field("name", 10);
        // 构造匹配查询条件
        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("address", "广州");
        // 构造范围查询条件
        RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("age").gt(10).lt(100);
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(multiMatchQueryBuilder);
        boolQueryBuilder.filter(matchQueryBuilder);
        boolQueryBuilder.filter(rangeQueryBuilder);
        // 将查询条件封装给查询对象
        searchSourceBuilder.query(boolQueryBuilder);
        request.source(searchSourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        for (SearchHit hit : hits) {
            String source = hit.getSourceAsString();
            System.out.println(source);
        }
        client.close();
    }

注意:range和term一次只能对一个Field设置范围过虑

排序,在查询的结果上进行二次排序,支持对 keyword、date、float 等类型添加排序,text类型的字段不允许排序

GET user/_search
{
    "query": {
        "bool": {
            "filter": [
                {
                    "range": {
                        "age": {
                            "gte": 10,
                            "lte": 100
                        }
                    }
                }
            ]
        }
    },
    "sort": [
        {
            "age": "desc" 
        }
    ]
}

    @Test
    // 排序
    public void getBySearch9() throws IOException {
        HttpHost host = HttpHost.create("http://192.168.16.188:9200");
        RestClientBuilder builder = RestClient.builder(host);
        client = new RestHighLevelClient(builder);
        SearchRequest request = new SearchRequest("user");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 构造范围查询条件
        RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("age").gt(10).lt(100);
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.filter(rangeQueryBuilder);
        searchSourceBuilder.sort("age", SortOrder.DESC);
        // 将查询条件封装给查询对象
        searchSourceBuilder.query(boolQueryBuilder);
        request.source(searchSourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        for (SearchHit hit : hits) {
            String source = hit.getSourceAsString();
            System.out.println(source);
        }
        client.close();
    }

根据查询条件来删除

@Test
    // 根据条件物理删除
    public void deleteBySearch() throws IOException {
        HttpHost host = HttpHost.create("http://192.168.16.188:9200");
        RestClientBuilder builder = RestClient.builder(host);
        client = new RestHighLevelClient(builder);
        DeleteByQueryRequest request = new DeleteByQueryRequest("efshdx"); // 替换成您的索引名称
        MatchPhraseQueryBuilder matchPhraseQueryBuilder = QueryBuilders.matchPhraseQuery("catagoryId", "1640927455451201537");
        request.setQuery(matchPhraseQueryBuilder);
        BulkByScrollResponse response = client.deleteByQuery(request, RequestOptions.DEFAULT); // 替换成您的Elasticsearch客户端实例
        long deleted = response.getStatus().getDeleted();
        System.out.println("删除掉的es数:"+deleted);
        client.close();
    }

更新,或者新建属性

    @Test
    // 使用es的Update Mapping API来更新日期映射,或者新建属性
    public void updateDateMapping() throws IOException {
        HttpHost host = HttpHost.create("http://192.168.16.188:9200");
        RestClientBuilder builder = RestClient.builder(host);
        client = new RestHighLevelClient(builder);
        PutMappingRequest request = new PutMappingRequest("person1"); // 替换成您的索引名称
        XContentBuilder mappingBuilder = XContentFactory.jsonBuilder();
        mappingBuilder.startObject();
        {
            mappingBuilder.startObject("properties");
            {
                mappingBuilder.startObject("time1");
                {
                    mappingBuilder.field("type", "date");
                    mappingBuilder.field("format", "yyyy/MM/dd"); // 更新日期格式
                }
                mappingBuilder.endObject();
                mappingBuilder.startObject("time2");
                {
                    mappingBuilder.field("type", "date");
                    mappingBuilder.field("format", "yyyy/MM/dd"); // 更新日期格式
                }
                mappingBuilder.endObject();
            }
            mappingBuilder.endObject();
        }
        mappingBuilder.endObject();
        request.source(mappingBuilder);
        AcknowledgedResponse response = client.indices().putMapping(request, RequestOptions.DEFAULT); // 替换成您的Elasticsearch客户端实例

        client.close();
    }

创建索引并添加属性

@Test
    // 创建索引并添加属性
    public void addIndexAndMapping() throws IOException {
        HttpHost host = HttpHost.create("http://192.168.16.188:9200");
        RestClientBuilder builder = RestClient.builder(host);
        client = new RestHighLevelClient(builder);
        CreateIndexRequest request = new CreateIndexRequest("person1"); // 替换成您的索引名称
        XContentBuilder mappingBuilder = XContentFactory.jsonBuilder();
        mappingBuilder.startObject();
        {
            mappingBuilder.startObject("properties");
            {
                // 添加字符串类型字段
                mappingBuilder.startObject("string-field");
                {
                    mappingBuilder.field("type", "text");
                }
                mappingBuilder.endObject();

                // 添加整数类型字段
                mappingBuilder.startObject("integer-field");
                {
                    mappingBuilder.field("type", "integer");
                }
                mappingBuilder.endObject();

                // 添加日期类型字段
                mappingBuilder.startObject("date-field");
                {
                    mappingBuilder.field("type", "date");
                    mappingBuilder.field("format", "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis");
                }
                mappingBuilder.endObject();

                // 添加嵌套类型字段
                mappingBuilder.startObject("nested-field");
                {
                    mappingBuilder.field("type", "nested");
                    mappingBuilder.startObject("properties");
                    {
                        mappingBuilder.startObject("nested-string-field");
                        {
                            mappingBuilder.field("type", "text");
                        }
                        mappingBuilder.endObject();
                    }
                    mappingBuilder.endObject();
                }
                mappingBuilder.endObject();
            }
            mappingBuilder.endObject();
        }
        mappingBuilder.endObject();
        request.mapping(mappingBuilder);
        CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT); // 替换成您的Elasticsearch客户端实例

        client.close();
    }