ES6.8.6 Java客户端发起 增删改查 query (bool)、update、delete

文章目录

环境

  • elasticsearch6.8.6版本:已安装ik分词器、icu分词器、pinyin分词器(分词器版本要和es版本一致)

测试数据

测试数据使用配置了ik分词器的索引:ik_news

初始化测试数据,在测试过程中可能发生修改、新增或删除。

单个新增

java 复制代码
    @Autowired
    private ElasticsearchRestTemplate restTemplate;
	
	/*

        ==================================
        https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/java-docs.html
        官网提供了java 操作api教程
     */
    @Test
    public void addOrUpdateOne() {

        String index = "ik_news"; // 索引名
        String type = "_doc"; // 文档类型

        // 模拟插入的数据
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("id", 12);
        dataMap.put("title", "ES客户端请求超时问题排查 - 爱定小闹钟 - 博客园");
        dataMap.put("uv", 500);
        dataMap.put("create_date", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        dataMap.put("status", 1);
        dataMap.put("remark", "来源博客园");

        // 更新请求
        UpdateRequest updateRequest = new UpdateRequest(index, type, MapUtil.getStr(dataMap, "id"));
        // 需要更新或插入的数据
        updateRequest.doc(dataMap);
        // 更新目标存在更新,不存在新增,如果不设置在找不到_id对应值的时候,直接报错
        updateRequest.docAsUpsert(true);

        try {
            UpdateResponse updateResponse = restTemplate.getClient().update(updateRequest, RequestOptions.DEFAULT);
            // 更新后数据从内存刷新到磁盘,实时刷新可能会影响性能
            // restTemplate.refresh(index);
            System.out.println(updateResponse);
        } catch (Exception e) {
            System.out.println("ES数据更新失败:" + e.getMessage());
        }
    }

批量新增

create_date: 字段原写错为:create_data,后来发现更正,见【删-->删除索引中指定字段】目录删除错误的字段写入。

java 复制代码
    @Autowired
    private ElasticsearchRestTemplate restTemplate;

    /*
        https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/java-docs-bulk.html
        官网提供:批量更新示例
     */
    @Test
    public void addOrUpdateBatch() throws IOException {

        String index = "ik_news"; // 索引名
        String type = "_doc"; // 文档类型

        List<Map<String, Object>> dataList = new ArrayList<>();
        // 模拟批量更新数据
    	// create_date: 字段原写错为:create_data,后来发现更正【见删--删除索引中指定字段】删除错误的写入。
        Map<String, Object> dataMap1 = new HashMap<>();
        dataMap1.put("id", 13);
        dataMap1.put("title", "Es 超时设置 high-level-client_es highlevelclient-CSDN博客");
        dataMap1.put("uv", 200);
        dataMap1.put("create_date", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
        dataMap1.put("status", 1);
        dataMap1.put("remark", "来源CSDN博客");

        Map<String, Object> dataMap2 = new HashMap<>();
        dataMap2.put("id", 14);
        dataMap2.put("title", "ES客户端请求超时问题排查 - 爱定小闹钟 - 博客园");
        dataMap2.put("uv", 259);
        dataMap2.put("create_date", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
        dataMap2.put("status", 1);
        dataMap2.put("remark", "来源博客园");

        dataList.add(dataMap1);
        dataList.add(dataMap2);

        BulkRequest bulkRequest = new BulkRequest(index, type);

        for (Map<String, Object> map : dataList) {

            UpdateRequest updateRequest = new UpdateRequest(index, type, MapUtil.getStr(map, "id"));
            updateRequest.doc(map);
            updateRequest.docAsUpsert(true);
            // 加入批量
            bulkRequest.add(updateRequest);
        }

        try {
            BulkResponse bulkResponse = restTemplate.getClient().bulk(bulkRequest, RequestOptions.DEFAULT);

            // 更新后数据从内存刷新到磁盘,实时刷新可能会影响性能
            // restTemplate.refresh(index);
            System.out.println(bulkResponse);
        } catch (Exception e) {
            System.out.println("ES数据批量更新失败:" + e.getMessage());
        }
    }

通过delete by api删除

删除_id=8的记录

java 复制代码
    @Autowired
    private ElasticsearchRestTemplate restTemplate;


	@Test
    public void deleteOne() {
        String index = "ik_news"; // 索引名
        String type = "_doc"; // 文档类型

        long id = 8L;

        DeleteRequest deleteRequest = new DeleteRequest(index, type, Long.toString(id));

        try {
            DeleteResponse response = restTemplate.getClient().delete(deleteRequest, RequestOptions.DEFAULT);

            System.err.println(response.getResult());
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("删除记录失败!");
        }

    }

通过delete by query api删除

删除create_date值为null或者空字符。

条件删除一定要慎重使用,一旦查询的字段名写错,造成全查询,那就game over了。

java 复制代码
    @Autowired
    private ElasticsearchRestTemplate restTemplate;

    /**
     * 通过查询条件删除
     */
    @Test
    public void deleteByQuery() {
        String index = "ik_news"; // 索引名
        String type = "_doc"; // 文档类型

        DeleteByQueryRequest deleteByQueryRequest = new DeleteByQueryRequest(index);

        deleteByQueryRequest.setBatchSize(100);
        deleteByQueryRequest.setDocTypes(type);
        deleteByQueryRequest.setRefresh(true);

        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        // 判断create_date为null
        boolQuery.mustNot(QueryBuilders.existsQuery("create_date"));
        deleteByQueryRequest.setQuery(boolQuery);


        try {
            restTemplate.getClient().deleteByQuery(deleteByQueryRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("批量删除失败!");
        }


    }

删除索引中指定字段(script)

如果在添加数据的时候,字段名写错了,需要在当前索引中删除指定字段。

java客户端请求:删除索引中字段名create_data

java 复制代码
	
    @Autowired
    private ElasticsearchRestTemplate restTemplate;

	/*
        删除索引中指定的字段
        https://www.cnblogs.com/8765h/p/17318622.html
        //
        https://blog.csdn.net/weixin_43823808/article/details/119930308
        //
        https://www.yisu.com/ask/28519983.html
     */
    @Test
    public void deleteField() throws IOException {
        String index = "ik_news"; // 索引名
        String type = "_doc"; // 文档类型

        /*

            mapping数据结构:
                {
                    "properties": {
                        "field_1": {
                            "type": "keyword",
                            "fields": {
                                "keyword": {
                                    ...
                                }
                            }
                        }
                    }
                }
         */

        // 需要移除的字段
        String[] filedNames = {"create_data"};


        // 获取索引中已经存在的索引
        Map<String, Object> mapping = restTemplate.getMapping(index, type);
        Map properties = MapUtil.get(mapping, "properties", Map.class);


        for (Object o : properties.keySet()) {
            // key:索引中字段名
            String key = o.toString();

            // 判断需要删除的字段,是否在索引中,如果在当前索引中,删除
            if (Arrays.stream(filedNames).collect(Collectors.toList()).contains(key)) {
                UpdateByQueryRequest request = new UpdateByQueryRequest(index);
                // 匹配文档中所有数据,需要一条一条做更新
                request.setQuery(QueryBuilders.matchAllQuery());
                // 把字段设置为null
                // request.setScript(new Script(ScriptType.INLINE, "painless", "ctx._source." + key + " = null", new HashMap<>()));
                // 使用remove直接把字段移除
                request.setScript(new Script(ScriptType.INLINE, "painless", "ctx._source.remove('" + key + "')", new HashMap<>()));
                request.setBatchSize(1000);
                request.setRefresh(true);
                try {
                    BulkByScrollResponse bulkByScrollResponse = restTemplate.getClient().updateByQuery(request, RequestOptions.DEFAULT);

                } catch (IOException e) {
                    System.err.println("删除字段错误");
                }
            }
        }
    }

单个修改update by api

java 复制代码
    @Test
    public void updateOne() {
        String index = "ik_news"; // 索引名
        String type = "_doc"; // 文档类型

        // 模拟修改的数据
        // 不需要修改的字段不要写在这里,仅会对指定字段更新
        Map<String, Object> dataMap = new HashMap<>();
        // id找不到的记录会报错:
        // Elasticsearch exception [type=document_missing_exception, reason=[_doc][122]: document missing]
        dataMap.put("id", 12);
        dataMap.put("title", "ES客户端请求超时问题排查 - 爱定小闹钟");
        dataMap.put("uv", 520);
        dataMap.put("create_date", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
        // 写错的字段会插入到记录里面
        // dataMap.put("create_data", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));

        // 更新请求
        UpdateRequest updateRequest = new UpdateRequest(index, type, MapUtil.getStr(dataMap, "id"));
        // 需要更新或插入的数据
        updateRequest.doc(dataMap);
        // 更新目标存在更新,不存在新增,在只允许修改的情况下这一段一定要注释掉。注释后如果修改的记录不存在会报错.
        // updateRequest.docAsUpsert(true);

        try {
            UpdateResponse updateResponse = restTemplate.getClient().update(updateRequest, RequestOptions.DEFAULT);
            // 更新后数据从内存刷新到磁盘,实时刷新可能会影响性能
            // restTemplate.refresh(index);
            System.out.println(updateResponse);
        } catch (Exception e) {
            System.out.println("ES数据更新失败:" + e.getMessage());
        }
    }

通过_bulk批量修改

java 复制代码
    @Test
    public void updateBatch() throws IOException {

        String index = "ik_news"; // 索引名
        String type = "_doc"; // 文档类型

        List<Map<String, Object>> dataList = new ArrayList<>();
        // 模拟更新数据
        Map<String, Object> dataMap1 = new HashMap<>();
        dataMap1.put("id", 13);
        dataMap1.put("title", "Es 超时设置 high-level-client_es highlevelclient-CSDN博客");
        dataMap1.put("uv", 200);
        dataMap1.put("create_date", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
        dataMap1.put("status", 1);
        dataMap1.put("remark", "来源CSDN博客");

        Map<String, Object> dataMap2 = new HashMap<>();
        dataMap2.put("id", 14);
        dataMap2.put("title", "ES客户端请求超时问题排查 - 爱定小闹钟 - 博客园");
        dataMap2.put("uv", 259);
        dataMap2.put("create_date", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
        dataMap2.put("status", null); // 设置为null
        dataMap2.put("remark", null); // 设置为null

        dataList.add(dataMap1);
        dataList.add(dataMap2);

        BulkRequest bulkRequest = new BulkRequest(index, type);

        for (Map<String, Object> map : dataList) {

            UpdateRequest updateRequest = new UpdateRequest(index, type, MapUtil.getStr(map, "id"));
            updateRequest.doc(map);
            // 更新目标存在更新,不存在新增,在只允许修改的情况下这一段一定要注释掉。注释后如果修改的记录不存在会报错.
            // updateRequest.docAsUpsert(true);
            // 加入批量
            bulkRequest.add(updateRequest);
        }

        try {
            BulkResponse bulkResponse = restTemplate.getClient().bulk(bulkRequest, RequestOptions.DEFAULT);

            // 更新后数据从内存刷新到磁盘,实时刷新可能会影响性能
            // restTemplate.refresh(index);
            System.out.println(bulkResponse);
        } catch (Exception e) {
            System.out.println("ES数据批量更新失败:" + e.getMessage());
        }
    }

批量修改update by query api

ES官网:无法对 null 值进行索引或搜索。当字段设置为 null (或空数组或值数组)时,该字段将被视为没有 null 值。

ES官网:由于各种原因,文档字段的索引值可能不存在

需要注意的是,如果字段值设置为显示的null(空数组也不会被索引),那这个字段不会被es索引,所以通过某个字段=null是查不到数据的,但是可以在创建索引的时候指定null_value=NULL进行替换:

latex 复制代码
{
    "settings": {
        "analysis": {
            "analyzer": {
                "default": {
                    "type": "ik_max_word"
                }
            }
        }
    },
    "mapping": {
        "_doc": {
            "properties": {
                // null_value设置示例
                "create_date": {
                    "type": "date",
                    "null_value": "NULL"
                }
            }
        }
    }
}

由于索引中未设置null_value替换,所以不能查询null的值去更新了。

java 复制代码
    @Test
    public void updateByQuery() {

        // 把所有status存在的数据时间和status进行更新

        String index = "ik_news"; // 索引名
        String type = "_doc"; // 文档类型

        UpdateByQueryRequest updateByQueryRequest = new UpdateByQueryRequest(index);
        updateByQueryRequest.setDocTypes(type);
        updateByQueryRequest.setRefresh(true);
        updateByQueryRequest.setBatchSize(100);

        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must(QueryBuilders.existsQuery("status"));

        updateByQueryRequest.setQuery(boolQuery);
        // 需要更新的数据
        updateByQueryRequest.setScript(new Script(ScriptType.INLINE, "painless", "ctx._source.create_date = " + new SimpleDateFormat("yyyy-MM-dd").format(new Date()) + "", new HashMap<>()));
        updateByQueryRequest.setScript(new Script(ScriptType.INLINE, "painless", "ctx._source.status = 2", new HashMap<>()));

        try {
            BulkByScrollResponse updatedByQuery = restTemplate.getClient().updateByQuery(updateByQueryRequest, RequestOptions.DEFAULT);

            System.out.println(updatedByQuery);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

使用script脚本修改

注!使用条件查询进行更新或者删除一定要慎重,因为一旦条件写错可能会造成全查询,数据更新错误或者删除错误。

java 复制代码
    /**
     * 通过脚本更新数据
     */
    @Test
    public void updateByScript() {
        String index = "ik_news"; // 索引名
        String type = "_doc"; // 文档类型

        UpdateByQueryRequest request = new UpdateByQueryRequest(index);
        // 匹配文档中所有数据,需要一条一条做更新
        // 把ID为11的数据,时间更新为null,状态更新为null
        request.setQuery(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("id", 11)));
        // 把字段设置为null
        request.setScript(new Script(ScriptType.INLINE, "painless", "ctx._source.create_date = null", new HashMap<>()));
        request.setScript(new Script(ScriptType.INLINE, "painless", "ctx._source.status = null", new HashMap<>()));
        request.setBatchSize(1000);
        request.setDocTypes(type);
        request.setRefresh(true);
        try {
            BulkByScrollResponse bulkByScrollResponse = restTemplate.getClient().updateByQuery(request, RequestOptions.DEFAULT);

            System.out.println("更新:" + bulkByScrollResponse.getUpdated());
        } catch (IOException e) {
            System.err.println("更新字段错误!");
        }
    }

完全匹配(term)

java 复制代码
    /**
     * 完全匹配查询: term进行更精准的查询匹配
     */
    @Test
    public void selectByBoolQueryTerm() {
        String index = "ik_news"; // 索引名
        String type = "_doc"; // 文档类型

        SearchRequest searchRequest = new SearchRequest();

        searchRequest.indices(index);
        searchRequest.types(type);

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        // text类型的字段,要term查询需要加上".keyword"
        sourceBuilder.query(boolQuery.must(QueryBuilders.termQuery("title.keyword", "ES客户端请求超时问题排查 - 爱定小闹钟 - 博客园")));

        searchRequest.source(sourceBuilder);

        try {
            SearchResponse search = restTemplate.getClient().search(searchRequest, RequestOptions.DEFAULT);

            for (SearchHit hit : search.getHits().getHits()) {
                System.out.println(hit.getSourceAsMap());
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

分词(match)

java 复制代码
    @Test
    public void selectByBoolQueryMatch() {
        String index = "ik_news"; // 索引名
        String type = "_doc"; // 文档类型

        SearchRequest searchRequest = new SearchRequest();

        searchRequest.indices(index);
        searchRequest.types(type);

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        // 匹配所有包含:"三毛"、"三"、"毛"的数据
        sourceBuilder.query(boolQuery.must(QueryBuilders.matchQuery("title", "三毛")));

        searchRequest.source(sourceBuilder);

        try {
            SearchResponse search = restTemplate.getClient().search(searchRequest, RequestOptions.DEFAULT);

            for (SearchHit hit : search.getHits().getHits()) {
                System.out.println(hit.getSourceAsMap());
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

分词(match_phrase)

matchmatch_phrase有什么区别?
match_phrase可以指定分词匹配的间隔,比match匹配更严格一些。

java 复制代码
    @Test
    public void selectByBoolQueryMatchPhrase() {
        String index = "ik_news"; // 索引名
        String type = "_doc"; // 文档类型

        SearchRequest searchRequest = new SearchRequest();

        searchRequest.indices(index);
        searchRequest.types(type);

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        // 匹配所有包含:连续在一起的"三毛"的数据
        // slop指定的是分词匹配的间隔,0,代表无间隔,只能匹配到包含连续"三毛"的数据
        // 匹配方式比match更严格
        sourceBuilder.query(boolQuery.must(QueryBuilders.matchPhraseQuery("title", "三毛").slop(0)));

        searchRequest.source(sourceBuilder);

        try {
            SearchResponse search = restTemplate.getClient().search(searchRequest, RequestOptions.DEFAULT);

            for (SearchHit hit : search.getHits().getHits()) {
                System.out.println(hit.getSourceAsMap());
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

is null、空白字符

更新的数据见【改-->使用script脚本修改】目录。

无法查询到索引数据(null,[]无法被索引)见【改-->批量修改update by query api】目录。

java 复制代码
    /**
     * 布尔查询
     */
    @Test
    public void selectByBoolQuery() {
        String index = "ik_news"; // 索引名
        String type = "_doc"; // 文档类型

        SearchRequest searchRequest = new SearchRequest();

        searchRequest.indices(index);
        searchRequest.types(type);

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        // 查询 create_date = 空
        sourceBuilder.query(boolQuery.mustNot(QueryBuilders.existsQuery("create_date")));
        searchRequest.source(sourceBuilder);

        try {
            SearchResponse search = restTemplate.getClient().search(searchRequest, RequestOptions.DEFAULT);

            for (SearchHit hit : search.getHits().getHits()) {
                System.out.println(hit.getSourceAsMap());
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

不为null,不是空白字符

java 复制代码
    /**
     * 布尔查询
     */
    @Test
    public void selectByBoolQuery2() {
        String index = "ik_news"; // 索引名
        String type = "_doc"; // 文档类型

        SearchRequest searchRequest = new SearchRequest();

        searchRequest.indices(index);
        searchRequest.types(type);

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        // 查询 create_date is not null and status is not null
        sourceBuilder.query(boolQuery.must(QueryBuilders.existsQuery("create_date")));
        sourceBuilder.query(boolQuery.must(QueryBuilders.existsQuery("status")));

//        sourceBuilder.query(boolQuery.mustNot(QueryBuilders.existsQuery("create_date")));
//        sourceBuilder.query(boolQuery.mustNot(QueryBuilders.existsQuery("status")));
        searchRequest.source(sourceBuilder);

        try {
            SearchResponse search = restTemplate.getClient().search(searchRequest, RequestOptions.DEFAULT);

            for (SearchHit hit : search.getHits().getHits()) {
                System.out.println(hit.getSourceAsMap());
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

通配符(?、*)

java 复制代码
    @Test
    public void selectByBoolQuery3() {
        String index = "ik_news"; // 索引名
        String type = "_doc"; // 文档类型

        SearchRequest searchRequest = new SearchRequest();

        searchRequest.indices(index);
        searchRequest.types(type);

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        // 参考关于通配符的使用:https://blog.csdn.net/HiBoyljw/article/details/90747211
        // 不加".keyword",会给分词,所以查不到结果了。
        sourceBuilder.query(boolQuery.must(QueryBuilders.wildcardQuery("title.keyword", "*天才作家*")));

        searchRequest.source(sourceBuilder);

        try {
            SearchResponse search = restTemplate.getClient().search(searchRequest, RequestOptions.DEFAULT);

            for (SearchHit hit : search.getHits().getHits()) {
                System.out.println(hit.getSourceAsMap());
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

排序(sort)

java 复制代码
    @Test
    public void selectByBoolQueryMatchAllSort() {
        String index = "ik_news"; // 索引名
        String type = "_doc"; // 文档类型

        SearchRequest searchRequest = new SearchRequest();

        searchRequest.indices(index);
        searchRequest.types(type);

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 查询所有
        sourceBuilder.query(QueryBuilders.matchAllQuery());
        // 多条件排序可以通过设置多个sort
        // 在时间升序的基础上,id升序
        // 按时间升序排序
        sourceBuilder.sort("create_date", SortOrder.ASC);
        // 按ID升序排序
        sourceBuilder.sort("id", SortOrder.ASC);

        searchRequest.source(sourceBuilder);

        try {
            SearchResponse search = restTemplate.getClient().search(searchRequest, RequestOptions.DEFAULT);

            for (SearchHit hit : search.getHits().getHits()) {
                System.out.println(hit.getSourceAsMap());
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

范围查询(rangeQuery)

java 复制代码
    @Test
    public void selectByRangeQuery() {
        String index = "ik_news"; // 索引名
        String type = "_doc"; // 文档类型

        SearchRequest searchRequest = new SearchRequest();

        searchRequest.indices(index);
        searchRequest.types(type);

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 范围查询 2024-01-22 <= time <= 2024-01-25
        sourceBuilder.query(QueryBuilders.rangeQuery("create_date").gte("2024-01-22").lte("2024-01-25"));

        searchRequest.source(sourceBuilder);

        try {
            SearchResponse search = restTemplate.getClient().search(searchRequest, RequestOptions.DEFAULT);

            for (SearchHit hit : search.getHits().getHits()) {
                System.out.println(hit.getSourceAsMap());
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

查询结果打印:

latex 复制代码
{uv=131, remark=来源网易科技, id=9, title=网易公布2022年第三季度财报|净收入|毛利润, create_date=2024-01-22, status=2}
{uv=310, remark=来源新浪财经, id=10, title=单季盈利超100亿元!比亚迪三季度毛利率超特斯拉, create_date=2024-01-23, status=2}
{uv=200, remark=来源知乎搜索, id=6, title=超全整理!三毛最出名的11本著作,没读过的一定要看看, create_date=2024-01-23, status=2}

must、should、filter

ES官网:查询和筛选上下文

ES官网:布尔查询

The minimum_should_match parameter possible values

  1. must

    子句(查询)必须出现在匹配的文档中,并计入分数。

  2. should

    子句 (query) 应出现在匹配的文档中。如果查询位于 bool 查询上下文中并且具有 must or filter 子句,则即使所有查询都不匹配,文档也会与 bool should 查询匹配。在这种情况下,这些子句仅用于影响分数。如果查询位于筛选器上下文中,或者两者都没有 must , filter 则必须至少有一个查询与文档匹配,才能使 bool 文档与 bool should 查询匹配。可以通过设置 minimum_should_match 参数来显式控制此行为。

  3. filter

    子句(查询)必须出现在匹配的文档中。但是,与查询的分数不同的 must 是,查询将被忽略。筛选器子句在筛选器上下文中执行,这意味着将忽略评分,并考虑将子句用于缓存。

三者聚合查询实例:

java 复制代码
    @Test
    public void selectMustShouldFilter() {
        String index = "ik_news"; // 索引名
        String type = "_doc"; // 文档类型

        SearchRequest searchRequest = new SearchRequest();

        searchRequest.indices(index);
        searchRequest.types(type);

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        // must必须匹配status=2
        sourceBuilder.query(boolQuery.must(QueryBuilders.termQuery("status", 2))); // ok
        // should至少包含n个筛选条件, 需要指定参数minimum_should_match = n
        sourceBuilder.query(boolQuery.should(QueryBuilders.wildcardQuery("remark.keyword", "*百度*")));
        // 设置符合must后,至少还要包含一个能匹配到should条件的参数。如果不配置此参数,should条件将不生效,设置1是在must筛选之后再匹配一遍参数
        boolQuery.minimumShouldMatch(1);
        // filter: 过滤uv >= 150的数据
        sourceBuilder.query(boolQuery.filter(QueryBuilders.rangeQuery("uv").gte(150)));

        searchRequest.source(sourceBuilder);

        try {
            SearchResponse search = restTemplate.getClient().search(searchRequest, RequestOptions.DEFAULT);

            for (SearchHit hit : search.getHits().getHits()) {
                System.out.println(hit.getSourceAsMap());
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

查询结果:

latex 复制代码
{uv=300, remark=来源百度知道, id=7, title=三毛的英文名为什么叫Echo?, create_date=2024-01-21, status=2}

更多查询:待补充...

待补充...

异常

执行更新操作UpdateRequest:索引中存在记录更新,不存在记录新建。

java.net.SocketTimeoutException: 30,000 milliseconds timeout on connection http-outgoing-0 [ACTIVE]

解决方式:

  1. 配置连接超时时间大于30s:未解决

    这是从异常情况直观看到的,就是连接超时,但是具体因为什么超时的未知。

    配置超时时间,这也是网上大多数给到的答案,但是没有解决我的问题。

  2. 先查询记录,然后再修改:未解决

    同时看到网上说es有个bug,先查询,再修改就不会出现超时的错误,但是没有说的哪个版本的问题,我试了一下没有解决。

  3. 修改配置文件:问题解决

    因为我是在windows系统上做的测试,下载es之后就直接启动了,没有对配置文件elasticsearch.yml做任何配置。

    我用postman发起http请求做测试的时候,增删改查都是成功的。但是配置Java客户端发起请求就失败了!!

Java配置:

yaml 复制代码
spring:
  # es连接配置
  elasticsearch:
    rest:
      uris: 127.0.0.1:9200
      username:
      password:

一般,单机上.yml需要修改几个内容:

yaml 复制代码
cluster.name: master
node.name: node-1
path.data: /path/to/data
path.logs: /path/to/logs
network.host: 0.0.0.0
http.port: 9200

修改之后,重启es,重新发起更新请求,成功了!!!

相关推荐
JerryXZR6 小时前
前端开发中ES6的技术细节二
前端·javascript·es6
JerryXZR1 天前
前端开发中常见的ES6技术细节分享一
前端·javascript·es6
前端李易安1 天前
ES6中WeakSet数据结构的常用方法和使用场景
java·javascript·es6
王解2 天前
掌握 Jest 中的模拟函数:提升单元测试的效率与可靠性
前端·javascript·单元测试·es6
王解3 天前
掌握 Jest 配置文件:优化单元测试的灵活性与可维护性
前端·javascript·单元测试·es6
GIS程序媛—椰子3 天前
【ES6】
前端·ecmascript·es6
一个W牛3 天前
ES6中数组新增了哪些扩展?
前端·前端框架·ecmascript·es6·jquery
anyup_前端梦工厂6 天前
重学前端 File、Blob、FileReader 基础知识学习
前端·javascript·es6
Star Universe8 天前
【React系列六】—React学习历程的分享
前端·javascript·学习·react.js·es6
前端郭德纲9 天前
深入浅出ES6 Promise
前端·javascript·es6