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

文章目录

    • 环境
    • 测试数据
      • 单个新增
      • 批量新增
      • 通过`delete by api`删除
      • 通过`delete by query api`删除
      • 删除索引中指定字段(script)
      • 单个修改`update by api`
      • 通过`_bulk`批量修改
      • 批量修改`update by query api`
      • 使用script脚本修改
      • 完全匹配(term)
      • 分词(match)
      • 分词(match_phrase)
      • is null、空白字符
      • 不为null,不是空白字符
      • 通配符(?、*)
      • 排序(sort)
      • 范围查询(rangeQuery)
      • must、should、filter
      • 更多查询:待补充...
    • 异常

环境

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

测试数据

测试数据使用配置了ik分词器的索引:ik_news
初始化测试数据,在测试过程中可能发生修改、新增或删除。
image.png

单个新增


    @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,后来发现更正,见【删–>删除索引中指定字段】目录删除错误的字段写入。




    @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的记录

    @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了。

    @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)

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

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

	
    @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


    @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批量修改

    @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进行替换:

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

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


    @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脚本修改

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


    /**
     * 通过脚本更新数据
     */
    @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)


    /**
     * 完全匹配查询: 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)


    @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匹配更严格一些。


    @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】目录。


    /**
     * 布尔查询
     */
    @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,不是空白字符

    /**
     * 布尔查询
     */
    @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();
        }
    }

通配符(?、*)

    @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)


    @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)

    @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();
        }
    }

查询结果打印:

{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 是,查询将被忽略。筛选器子句在筛选器上下文中执行,这意味着将忽略评分,并考虑将子句用于缓存。

        三者聚合查询实例:

image.png

    @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();
        }
    }

查询结果:

{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]

image.png
解决方式:

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

            这是从异常情况直观看到的,就是连接超时,但是具体因为什么超时的未知。
            配置超时时间,这也是网上大多数给到的答案,但是没有解决我的问题。

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

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

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

            因为我是在windows系统上做的测试,下载es之后就直接启动了,没有对配置文件elasticsearch.yml做任何配置。
            我用postman发起http请求做测试的时候,增删改查都是成功的。但是配置Java客户端发起请求就失败了!!

        Java配置:

spring:
  # es连接配置
  elasticsearch:
    rest:
      uris: 127.0.0.1:9200
      username:
      password:

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/366273.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Qt基本功修炼】Qt线程的两种运行模式

1. 前言 QThread是Qt中的线程类&#xff0c;用于实现多线程运行。 QThread有两种工作模式&#xff0c;即 消息循环模式无消息循环模式 两种模式分别适用于不同的场景。下面我们将从多个方面&#xff0c;讲解QThread两种工作模式的区别。 2. 消息循环模式 2.1 实现原理 Q…

nightinage部署

git开源地址 GitHub - ccfos/nightingale: An all-in-one observability solution which aims to combine the advantages of Prometheus and Grafana. It manages alert rules and visualizes metrics, logs, traces in a beautiful web UI. 一、下载源码自己编译运行 二、用…

在本机搭建私有NuGet服务器

写在前面 有时我们不想对外公开源码&#xff0c;同时又想在VisualStudio中通过Nuget包管理器来统一管理这些内部动态库&#xff0c;这时就可以在本地搭建一个NuGet服务器。 操作步骤 1.下载BaGet 这是一个轻量级的NuGet服务器 2.部署BaGet 将下载好的release版本BaGet解…

字符下标计数

下标计数 数组计数&#xff0c;即通过使用一个新的数组&#xff0c;对原来数组里面的项进行计数&#xff0c;统计原来数组中各项出现的次数&#xff0c;如下图所示&#xff1a; 数组计数可以方便快速地统计出一个各项都比较小的数组中&#xff0c;数值相同的数的个数。 数组计数…

代码随想录算法训练营DAY10 | 栈与队列 (1)

理论基础及Java实现参考文章&#xff1a;栈和队列 一、LeetCode 232 用栈实现队列 题目链接&#xff1a;232.用栈实现队列https://leetcode.cn/problems/implement-queue-using-stacks/ 思路&#xff1a;使用两个栈stack1、stack2实现队列&#xff1b;stack1用来存储入队元素&…

【Servlet】——Servlet API 详解

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【Servlet】 本专栏旨在分享学习Servlet的一点学习心得&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 一、HttpServlet二、Htt…

图像处理之《可逆重缩放网络及其扩展》论文精读

一、文章摘要 图像重缩放是一种常用的双向操作&#xff0c;它首先将高分辨率图像缩小以适应各种显示器或存储和带宽友好&#xff0c;然后将相应的低分辨率图像放大以恢复原始分辨率或放大图像中的细节。然而&#xff0c;非单射下采样映射丢弃了高频内容&#xff0c;导致逆恢复…

Flink的SQL开发

概叙 Flink有关FlinkSQL的官网: https://nightlies.apache.org/flink/flink-docs-release-1.13/zh/docs/dev/table/sql/overview/ 阿里云有关FlinkSQL的官网: https://help.aliyun.com/zh/flink/developer-reference/overview-5?spma2c4g.11186623.0.0.3f55bbc6H3LVyo Ta…

Mac 下文件编码转换的方法

Windows文件传输到Mac,在Windows上打开是可以看的,但是在Mac上打开是乱码,这是因为Windows默认是GBK编码,而Mac使用的是UTF-8编码,这时候需要对文件编码进行转换,以方便在Mac上查看和使用 iconv macOS 系统中&#xff0c;iconv 命令是一个用于转换文件或文本流的字符编码的实用…

Django模型(八)

一、修改数据 先获取对象,通过对象属性更新数据,再保存 (更新单一数据)通过QuerySet的update函数更新数据 (更新多条数据) #单条记录修改 save c = Cook.objects.get(pk=1) c.name = 安妮 c.save()# 更新多个值 update Cook.objects.filter(sect=粤菜).update(level=5)1.1、…

C# 根据USB设备VID和PID 获取设备总线已报告设备描述

总线已报告设备描述 DEVPKEY_Device_BusReportedDeviceDesc 模式 winform 语言 c# using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Window…

IntelliJ IDEA 2023和Java的JDK详细安装教程

一、软件下载 网盘链接&#xff1a;IntelliJ IDEA 2023 提取码&#xff1a;2syx 二、详细安装教程 1.鼠标右击【JetBrains2023】压缩包&#xff08;win11及以上系统需先点击“显示更多选项”&#xff09;选择【解压到 JetBrains2023】&#xff1b;打开解压后的文件夹&#x…

银行数据仓库体系实践(15)--数据应用之巴塞尔新资本协议

巴塞尔新资本协议介绍 在银行管理中经常会听到巴3、新资本协议等专用词&#xff0c;那这都是指《巴塞尔资本协议》&#xff0c;全称《关于统一国际银行资本衡量和资本标准的协议》。新资本协议的五大目标是&#xff1a;促进金融体系的安全性和稳健性&#xff08;保持总体资本水…

c++阶梯之auto关键字与范围for

auto关键字&#xff08;c11&#xff09; 1. auto关键字的诞生背景 随着程序的逐渐复杂&#xff0c;程序代码中用到的类型也越来越复杂。譬如&#xff1a; 类型难以拼写&#xff1b;含义不明确容易出错。 比如下面一段代码&#xff1a; #include <string> #include &…

(学习日记)2024.02.01:引用变量 / 默认实参 / 一元作用域运算符 / 函数重载

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…

踩坑STM32CubeMX生成Makefile工程无法使用printf(“%f“)

过去一年偶有接触STM32开发时都是使用STM32CubeMX生成Makefile的工程&#xff0c;具体开发环境见配置Clion用于STM32开发&#xff08;Makefile&#xff09;&#xff0c;但没想到今天在使用printf打印输出浮点数时无法正常输出&#xff0c;不仅printf无法使用&#xff0c;其他涉…

MongoDB从入门到实战之MongoDB快速入门

前言 上一章节主要概述了MongoDB的优劣势、应用场景和发展史。这一章节将快速的概述一下MongoDB的基本概念&#xff0c;带领大家快速入门MongoDB这个文档型的NoSQL数据库。 MongoDB从入门到实战的相关教程 MongoDB从入门到实战之MongoDB简介&#x1f449; MongoDB从入门到实战…

白皮书发布,石油石化数字孪生加速

近日&#xff0c;《数字石化 孪生智造——石油石化数字孪生白皮书》发布。白皮书聚焦石油石化行业发展机遇&#xff0c;剖析数字孪生技术在行业中的案例实践与应用场景&#xff0c;展望石油石化企业未来孪生发展新态势。 当前&#xff0c;国家大力推动减污降碳协同增效&#x…

【IM】长连接网关设计探索(一)

目录 1.长连接网关的必要性2. 设计目标2.1 技术挑战2.2 技术目标 3. 方案选型3.1 网关IP地址的选择3.1.1 使用httpDNS服务3.1.2 自建http server作为IP config server3.1.3 最佳方案 3.2 高并发收发设计3.2.1 C10K问题3.2.2 方案探索双协程监听channel实现全双工 一个定时器 1…

Unity学习之Unity核心(一)2D相关

文章目录 1. 前言2 图片导入概述3 图片设置的六大部分3.1 纹理类型3.1.1 Default3.1.2 Normal Map 法线贴图格式3.1.3 Editor GUI and Legacy GUI3.1.4 Sprite3.1.5 Cursor 自定义光标3.1.6 Cookie 光源剪影格式3.1.7 LightMap光照贴图格式3.1.8 Single Channel 纹理只需要单通…