美文网首页
Elasticsearch使用小结

Elasticsearch使用小结

作者: Corey1874 | 来源:发表于2022-03-04 21:40 被阅读0次

前言

ES大家可能都不陌生,它是一个高效的搜索引擎,可以帮助我们快速存储、搜索大量数据。

我工作中负责的模块之一,是一个核心存储服务,我们业务的数据通过这个服务存储到MySQL中,并向内部系统提供查询能力。我们主要数据被拆分成了两张表,因此面对各种各样的查询需求,如果只依赖MySQL本身的查询能力查询,会遇到几个问题:
1.如果需要查询的字段或者查询条件分别在两张表中,那么就需要联表查询。我们一般是不推荐join查询的。因为join的效率较低,如果数据量大的话,查询速度很难保证。

2.如果为了加快查询速度,最好对需要查询的字段建索引。那么作为底层存储服务,面对的查询需求是各种各样的,极端点的可能就是每个字段都可能需要被查询,如果对每个字段建立索引,会增加索引变更的维护成本,并且更多的索引需要占用的空间也更多,因此一般是不推荐表中索引列太多的。即时是只对高频查询字段建立索引,索引列的量仍然不少。

因此我们团队的解决方案是在ES中维护一份与数据库中一致的数据,存储的内容就是各种查询需求需要的字段和我们的唯一业务ID,即订单号。查询时先在ES中查出所有符合条件的订单号,再根据订单号从数据库的两张表中分别查出需要的数据返回。

实例

下面总结一些工作中遇到的比较棘手的查询需求

例1

有两个时间字段,order_datetime、order_create_time,以yyyy-MM-dd HH:mm:ss格式存储,需要查出所有符合order_datetime比order_create_time大30min的订单

解决方案:用脚本查询

Java实现如下:

        BoolQueryBuilder queryRequest = new BoolQueryBuilder();
        String scriptStr = "(doc['order_datetime'].value.getMillis() - doc['order_create_time'].value.getMillis())/(3600000.0/60) > 30"
        Map<String, Object> params = new HashMap<>();
        Script script = new Script(ScriptType.INLINE, "painless", scriptStr, params);
        ScriptQueryBuilder scriptQueryBuilder = new ScriptQueryBuilder(script);
        queryRequest.must(scriptQueryBuilder);

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(queryRequest);
        searchSourceBuilder.fetchSource(false);
        SearchRequest searchRequest = new SearchRequest();
        searchRequest.source(searchSourceBuilder);
        searchRequest.indices(Constants.ES_ORDER_INDEX);

        searchResponse = restHighLevelClient.search(searchRequest);

DSL:

{
    "from": 0,
    "size": 10,
    "query": {
        "bool": {
            "must": {
                "script": {
                    "script": {
                        "source": "(doc['order_datetime'].value.getMillis() - doc['create_time'].value.getMillis())/(3600000.0/60) >= 30",
                        "lang": "painless"
                    },
                    "boost": 1.0
                }
            }
        }
    },
    "_source": false
}

例2

某个字段price_plan有几种可能的值:1,2,3,4或null,为null的含义与为1相同。查询时的入参为多个值,如[2,3]表示查询出所有price_plan = 2或price_plan=3的数据,[1,4]表示查出所有price_plan = 1或price_plan=4或price_plan为空的数据。null的含义与为1相同是带来麻烦的核心点。

Java:

        BoolQueryBuilder queryRequest = new BoolQueryBuilder();
        if (!CollectionUtils.isEmpty(request.getPricePlan())) {
            BoolQueryBuilder queryShould = new BoolQueryBuilder();
            queryShould.should(new TermsQueryBuilder("price_plan", request.getPricePlan()));

            // 如果查询1,则应该把null也查出来
            if (request.getPricePlan().contains(1)){
                BoolQueryBuilder queryExist = new BoolQueryBuilder();
                ExistsQueryBuilder existsQueryBuilder = QueryBuilders.existsQuery("price_plan");
                queryExist.mustNot(existsQueryBuilder);
                queryShould.should(queryExist);
            }

            queryRequest.must(queryShould);
        }

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(queryRequest);
        searchSourceBuilder.fetchSource(false);
        SearchRequest searchRequest = new SearchRequest();
        searchRequest.source(searchSourceBuilder);
        searchRequest.indices(Constants.ES_ORDER_INDEX);

        searchResponse = restHighLevelClient.search(searchRequest);

DSL:

{
    "from": 0,
    "size": 10,
    "query": {
        "bool": {
            "must": [{
                "terms": {
                    "order_status": [0],
                    "boost": 1.0
                }
            }, {
                "bool": {
                    "should": [{
                        "terms": {
                            "price_plan": [1, 3, 2],
                            "boost": 1.0
                        }
                    }, {
                        "bool": {
                            "must_not": [{
                                "exists": {
                                    "field": "price_plan",
                                    "boost": 1.0
                                }
                            }],
                            "adjust_pure_negative": true,
                            "boost": 1.0
                        }
                    }]
                }
            }]
        }
    },
    "_source": false
}

相关文章

网友评论

      本文标题:Elasticsearch使用小结

      本文链接:https://www.haomeiwen.com/subject/aqimrrtx.html