首页 > 其他分享 >商超外卖搜索基于Elasticsearch的优化实践

商超外卖搜索基于Elasticsearch的优化实践

时间:2023-10-22 16:13:04浏览次数:27  
标签:www 我们 source Elasticsearch 商超 外卖 query guide store

业务背景

我们是外卖搜索系统,在传统的外卖的基础上,推出了便利超市的功能。但是与外卖商家不同的是,我们有很多大型的商超,每个商超的商品数量会非常多,导致线上调用ES大量超时且ES负载较重。

由于我们是多国家业务当前是根据国家拆分所以,以情况最为严重的泰国为例,有数万家商家,和几千万商品,尤其是一些超大型商超甚至有几十万商品。

商家document包含家所卖的商品名称item_names字段。

是否在配送范围又分为两种方式:CBR(city-based-radius,以用户为中心),MBR(merchant-based-radius,以商家为中心),所以我们的距离过滤语句为:

{
    "query":{
        "bool":{
            "must":[
                {
                    "bool":{
                        "minimum_should_match":"1",
                        "should":[
                            {
                                "bool":{
                                    "filter":[
                                        {
                                            "term":{
                                                "enabled_delivery_radius":0
                                            }
                                        },
                                        {
                                            "geo_distance":{
                                                "distance":"15000m",
                                                "distance_type":"plane",
                                                "geo_location":{
                                                    "lat":13.748888888888888,
                                                    "lon":100.55666666666666
                                                }
                                            }
                                        }
                                    ]
                                }
                            },
                            {
                                "bool":{
                                    "_name":"#mbr_query",
                                    "filter":[
                                        {
                                            "term":{
                                                "enabled_delivery_radius":1
                                            }
                                        },
                                        {
                                            "geo_shape":{
                                                "geometry":{
                                                    "relation":"contains",
                                                    "shape":{
                                                        "coordinates":[
                                                            100.55666666666666,
                                                            13.748888888888889
                                                        ],
                                                        "type":"point"
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        ]
                    }
                }
            ]
        }
    }
}

召回流程

我们是有多路召回,其中基于ES的召回分为召回商家和召回商品两步:

调整query

拆分query

我们知道,基于location的查询是比较耗时的,基于之前的实战经验,我们决定拆分query,将cbr和mbr拆分成并行的query(由于商超业务qps通常比较小,给es带来的qps不是那么多)
效果:由之前的600ms timeout 90% -> <1% p99 avg 500ms

深度分析

我们知道,es默认的search type是query_then_fetch,如上图所示。参考文档:https://www.elastic.co/guide/en/elasticsearch/guide/current/distributed-search.html

我们可以通过GET index/_stats来获取各个阶段的平均耗时。参考文档:https://www.elastic.co/guide/cn/elasticsearch/guide/current/_monitoring_individual_nodes.html

通过我们对比发现,在我们泰国商超索引fetch的速度很慢,fetch可以理解成查正排索引的过程,于是我们怀疑由于merchant索引上面的item_names过大导致解析数据效率下降,于是我们跑了含有string数组的结构体json.unmarshal的benchmark,从结果来看item越多解析越慢:

探索优化

使用docvalue_fields替换_source

关于docvalue_fieldshttps://www.elastic.co/guide/en/elasticsearch/reference/current/search-fields.html#docvalue-fields

  • 当取的字段比较少时非常快,但是当取的字段比较多时依旧很慢
  • 不支持text or text_annotated 字段
  • 不支持查询nested对象里面的值

使用_exclude来拿掉_source里面的一些字段

关于_exclude https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-source-field.htm

  • 标明_exclude的字段将会从_source里面移除
  • 即使它不存储在_source里面,我们依然可以在这个字段上搜索(倒排索引里面依然存在)
    由于我们商家索引里面的商品名只用来在keyword的匹配,而不需要返回给search服务,所以我们可以考虑拿掉_source里面的item_names字段。
    我们发现,即使不拆分query,cost也可以从600ms+降低到100ms-,同时store.size也从4.6G->2.4G。
    但是很遗憾的是,在更新时,我们使用了partial_update(我们使用了partial_update),在更新非item_names字段的时候,会导致item_names丢失,因为partial_update会在_source里面读取document然后替换想要更新的字段(https://www.elastic.co/guide/en/elasticsearch/reference/6.8/mapping-source-field.html)。

store

关于store (https://www.elastic.co/guide/en/elasticsearch/reference/6.8/mapping-store.html)ES官方给了个使用场景的例子:

In certain situations it can make sense to `store` a field. 
For instance, if you have a document with a `title`, a `date`, 
and a very large `content` field, 
you may want to retrieve just the `title` and the `date` without having to
 extract those fields from a large `_source` field

这很适合我们的场景,我们只需要把search时需要取的字段设置成store即可.顺带提一下,由于业务原因我们有nested(https://www.elastic.co/guide/en/elasticsearch/reference/current/nested.html)类型字段,对于nested里面的字段我们是无法设置store的,但是我们可以在nested外增加一些非nested字段,对这些字段进行单独store设置。

所以我们需要事情有:

索引服务:

  • 修改ES mapping,给需要返回的字段设置"store": true]
  • 从nested里面Copy不能设置store的字段把他们存到新字段里面并给新字段设置成store
    搜索服务
  • 默认的,我们是从source里面取的东西,对应json的key是_source
  • 对于商家索引,将从_source中获取信息改成从stored_fields中获取信息,解析返回的数组

在这个优化上线之后,对应索引的ES latency降低了32.5%,错误率降低了98.1%,可用性达到99.9+

标签:www,我们,source,Elasticsearch,商超,外卖,query,guide,store
From: https://www.cnblogs.com/wanber/p/17780571.html

相关文章

  • ElasticSearch 拼音分词和自动补全
    在搜索过程中,大部分情况下会有智能提示功能,也就是开头匹配的自动补全功能,这就需要用到ElasticSearch的Suggest查询功能。用户也可能输入拼音或者查询关键字的首字母简写,比如我想查询华为手机,我可以输入hwsj进行查询,这就需要用到拼音分词器。本篇博客将介绍如何安装拼音分词......
  • Elasticsearch的架构
    1.3Elasticsearch的架构Gateway层es用来存储索引文件的一个文件系统且它支持很多类型,例如:本地磁盘、共享存储(做snapshot的时候需要用到)、hadoop的hdfs分布式存储、亚马逊的S3。它的主要职责是用来对数据进行长持久化以及整个集群重启之后可以通过gateway重新恢复数据。Distributed......
  • 同城外卖跑腿小程序开发的关键步骤
    随着快节奏的生活方式和数字化技术的不断发展,外卖和跑腿服务变得越来越受欢迎。为了满足这一需求,越来越多的创业者和企业开始着手开发同城外卖跑腿小程序。本文将详细介绍同城外卖跑腿小程序开发的关键步骤,帮助您了解如何成功创建一个具有竞争力的应用程序。一、创意与市场研究在开......
  • 使用docker命令行为elasticsearch安装ik中文分词插件
    背景:mac+dockerdesktop+elasticsearch7.8.0 一、安装ik中文分词插件dockerexec-itelastic_search/bin/bash-c'bin/elasticsearch-plugininstallhttps://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.8.0/elasticsearch-analysis-ik-7.8.0......
  • elasticsearch 设置高亮
    1、引入配置springboot环境<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.2.RELEASE</version></parent>引入es配置<!--e......
  • Elasticsearch 7.17.7开启x-pack
    1、ES配置文件  elasticsearch.ymlcluster.name:elasticsearchnode.name:node-1network.host:0.0.0.0discovery.type:single-nodexpack.security.enabled:truexpack.security.authc.api_key.enabled:true设置密码/usr/share/elasticsearch/bin/elasticsearch-s......
  • elasticsearch 8.7.0的Java API详解教程(一)
    最近作者做一个es的搜索,之前采用的是7.12.1,本来接口都已经基本上写好了,后面es要升级到8.7.0,一升级就连接不上es8.7.0了,后面才发现原来es8是默认采用了HTTPS协议,需要配置认证证书,这个问题搞了好久好久,最后终于搞成功了,在此写一篇博客记录一下。一、pom文件<?xmlversion="1.0"encod......
  • Elasticsearch(ES):现代搜索与分析引擎
    大数据时代带来了海量的信息和数据,如何高效地管理、搜索和分析这些数据成为了企业和组织面临的重要挑战。在这个背景下,Elasticsearch应运而生,它是一款强大的开源搜索和分析引擎,广泛用于各种领域,从企业搜索、日志分析到监控系统,为用户提供了快速、准确的数据搜索和分析功能。1.什么......
  • ElasticSearch Java API 基本操作
    前言ElasticSearchJavaAPI是ES官方在8.x版本推出的新javaapi,也可以适用于7.17.x版本的es。本文主要参考了相关博文,自己手动编写了下相关操作代码,包括更新mappings等操作的java代码。代码示例已上传github。版本elasticsearch版本:7.17.9,修改/elasticsearch-7.17.9/config/......
  • docker安装elasticsearch:8.9.0的过程
    环境是CentOS7,elasticsearch:8.9.0。使用的是root用户首先创建挂载的目录,并且赋予777权限。第一步获取elasticsearch镜像dockerpullelasticsearch 第二步 查看镜像是否下载成功dockerimages 第三步宿主机上创建用到的挂载文件 cd/optmkdir/es_docker......