Elasticsearch使用小结

前言

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
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351

推荐阅读更多精彩内容

  • 这一篇最主要是记录下命令,方便以后查找 使用Mysql 创建数据库 create database mysql_t...
    Treehl阅读 576评论 0 0
  • # MongoDB ## 数据库分类 ### 关系型数据库 * 具备ACID特性 * Atomic原子性,也就...
    奥利奥_4e9e阅读 559评论 0 0
  • MySQL的基本操作可以包括两个方面:MySQL常用语句如高频率使用的增删改查(CRUD)语句和MySQL高级功能...
    wwmin_阅读 1,064评论 0 54
  • 1、dede_addonarticle:附加文章表 索引:PRIMARY KEY('aid'),KEY'typei...
    渝娃阅读 2,084评论 0 1
  • SQL学习 法则1:col table表/columns列/rows行 问题:movies表有100万数据? 法则...
    jessica涯阅读 553评论 0 1