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,重新发起更新请求,成功了!!!

相关推荐
漫谈网络1 小时前
TypeScript 编译 ES6+ 语法到兼容的 JavaScript介绍
javascript·typescript·es6
书语时4 天前
ES6 深克隆与浅克隆详解:原理、实现与应用场景
前端·javascript·es6
SuperherRo5 天前
Web攻防-SQL注入&增删改查&HTTP头&UA&XFF&Referer&Cookie&无回显报错
sql·referer·增删改查·cookie·xff·ua
一轮大月亮6 天前
JavaScript es6 语法 map().filter() 链式调用,语法解析 和常见demo
开发语言·javascript·es6
zlpzlpzyd11 天前
ecmascript 第6版特性 ECMA-262 ES6
前端·ecmascript·es6
电子科技圈11 天前
XMOS推出支持AES67标准的以太网音频解决方案——使高兼容性和低延迟专业音频传输及播放成为可能
前端·es6·音视频
超级土豆粉11 天前
ES6 扩展运算符与 Rest 参数
前端·ecmascript·es6
theMuseCatcher12 天前
手写ES6 Promise() 相关函数
javascript·es6
超级土豆粉13 天前
ES6 哈希数据结构
数据结构·es6·哈希算法
超级土豆粉13 天前
ES6 新增 API 方法
前端·ecmascript·es6