关于电商搜索中Elasticsearch的正确使用姿势--配置篇
文章目录
- 前言
- 什么是Elasticsearch
- ES快在哪里
- 创建索引
- 索引的基本配置
- 分片
- 分析器
- Field分析器应用
- copy_to
- multi-fields
- 结语
- 更新
前言
过年放假啦,总算是闲下来了,笔者自从上次文章更新之后经历了许多事情(裁员风波,面试找工作等等),最近总算是安定下来了。
言归正传,笔者在之前接触Elasticsearch很少,在新公司中,接触到了以电商搜索推荐为主的项目,其中就大量运用到了Elasticsearch(以下简称ES),并收获了不少经验。
本篇就来围绕如何在电商搜索中正确高效的使用ES聊聊笔者的一些心得。
什么是Elasticsearch
ES是一款分布式搜索引擎,这里注意点重点:搜索引擎,很显然,ES对于数据检索有非常多的设计和优化,在这方面有着得天独厚的优势。
ES底层基于 Lucene 实现,同时屏蔽了很多Lucene的底层细节,提供了分布式特性,同时对外提供了 Restful API,我们的所有针对ES的操作,可以直接通过发HTTP请求就可以完成了。
ES快在哪里
答案是 全文检索
想象这么一个场景,有1亿篇文章,现在想要通过搜索文章内容找到对应的文章。假设这些数据存储在mysql当中,能够做到吗。
当然是可以的,但是性能上就比较感人了,原因是由于mysql通常的索引底层实现(B+树)无法很好的实现上述匹配度查找,而使用like
语法查找则会导致索引失效,同样也会有性能问题(mysql 5.6之后开始支持全文索引,这些内容不在本文的描述范围之内,不过正如佛瑞德·布鲁克斯所说,软件工程没有银弹,不同场景下采用合适的技术才是解决问题更加有效率的方式)。
而ES基于分词 + 倒排索引,在匹配查询这方面性能上更加优异,操作也更加友好(restful,并且为nosql,数据格式十分灵活),关于ES检索的核心实现机制也不在本文的论述范围当中,兴趣的小伙伴可以自行谷歌学习。
而本文主要描述如何在检索项目(如电商搜索)中灵活使用ES实现对应需求
创建索引
首先需要提一句的是,在ES中,万物皆索引。这正是ES将检索功能发挥到极致的体现。由于是不同的数据库,术语的含义也有一些变化,为便于理解,这里使用mysql作为对比。
在ES中,一个索引(Index)即相当于mysql的一个数据库;一个类型(Type)相当于mysql的一张表(ES7以后舍弃了type的概念,一个索引只能有一个type);一个文档(Document)相当于mysql的一行记录;一个字段(Field)相当于记录中的一个属性。
ES | mysql |
---|---|
索引(Index) | 数据库 |
类型(Type) | 表 |
文档(Document) | 记录(行) |
字段(Field) | 属性(列) |
正如mysql中检索后出来的是若干条记录,ES检索出来的则是一条条文档,文档在ES中是被检索的最小单位。一般文档就长这样
{"_index": "mall","_type": "_doc","_id": "10104","_version": 6,"_score": 1,"_source": {"itemid": 10104,"title": "1500g铁观音赛君王安溪铁观音","pubtime": 1576152329,"ipname": "铁观音","brandid": 0,"brandname": "西湖牌","categoryid": 3,"logic_categoryid": ["1","2","3",],"commentnum": 2,"qualityscore": 2,"subscribenum": 2}
}
这是通过ES检索后返回的文档,标准的json格式,其中_index, _type
就是我们上述讲到的ES的存储结构;_id
相当于这条文档的主键,如果不主动设置的话ES会默认分配;
_score
是匹配分,ES会对每条查询结果打一个分数,评分机制比较复杂且灵活,只需要记住,分数越高,这条文档的相对于检索条件的匹配度就越高(ES的查询结果默认是按分数进行排序的)。
_version
是这条文档的版本号,每次对文档进行修改,版本号都会增加,版本号的作用在于保持数据的一致性。
最后的_source
就是文档本身的内容了,也就是我们的业务数据。
简单的介绍就到此为止,业务数据是上面那样,如果什么都不做,直接往ES里塞数据的话,ES会根据文档的属性Field
自动进行分词优化以达到快速检索的目的,但是实际上什么都不设置在工程中是几乎不存在的,我们或多或少会根据业务需求对每个字段进行单独设置。
打个比方来说,文档中的title(标题), ipname(ip名称), brandname(品牌名称)
正常来说我们都要进行分词,有时候用户检索不一定是中文,还可能是拼音,我们则需要对应的拼音分词(可以通过增加插件);又或者我们的品牌名称是一个生造词,这种时候通过分词器是识别不出这样的词汇的,我们也需要进行特定的设置。
当然,上述情况只是众多需要我们自定义索引结构的理由之一,下面我将通过一份索引配置来引出ES所提供的更多实用的功能。
索引的基本配置
分片
为了便于理解,我们把一份完整的配置拆分成若干单独的配置逐个查看
{"mall": {"settings": {"index": {"number_of_shards": "5","number_of_replicas": "1","analysis": {"filter": {...},"char_filter": {...},"analyzer": {...}}}},"mappings": {...},}
}
其中,number_of_shards
表示ES主分片的数量,这里的分片相当于的mysql的分库分表,这里ES自身实现了这个功能。number_of_replicas
表示复制分片的数量,复制分片相当于主分片的备份,上述设置表示为该索引设置5个分片,每个分片有一个备份。这也是ES的默认配置。
深入了解分片功能,可以看看这篇文章,本文不做过多赘述。
分析器
接下来我们看看analysis
中设置哪些内容
..."analysis": {"filter": {...},"char_filter": {...},"analyzer": {...}}
...
在上述配置中,主要分位3个部分,filter
、char_filter
、analyzer
,filter
,char_filter
表示过滤器,analyzer
为分析器(其实还有tokenizer
分词器,不过这里没有配置),这三者的关系为analyzer
包含filter
和char_filter
,实际的配置中可能更多,但大致都是analyzer
为最终的组合结果。
我们来看下analysis
部分的完整配置
{"mall": {"settings": {"index": {"number_of_shards": "5","number_of_replicas": "1","analysis": {"filter": {"my_synonym_filter": {"type": "synonym","synonyms_path": "analysis/synonyms.txt"},"origin_and_pinyin": {"keep_joined_full_pinyin": "true","type": "pinyin"}},"char_filter": {"tsconvert": {"convert_type": "t2s","type": "stconvert","keep_both": "false","delimiter": "#"}},"analyzer": {...}}}},"mappings": {}}
}
上述配置中,我们在filter
中配置了同义词过滤,这使得我们在面对一些生造词的商品也能够使得ES能够正确的进行分词。
my_synonym_filter
,这个名字是我们自己起的,在filter
中的key名字随便起,我们将在接下来对analyzer
中的配置中使用他们,其他配置项也是一样
同理,origin_and_pinyin
使得我们能够识别用户的拼音输入(使用的是medcl的elasticsearch-analysis-pinyin插件)
在char_filter中
,我们配置了tsconvert
,这使得我们能够识别用户输入的繁体字,并将其匹配对应的简体字。采用的插件为elasticsearch-analysis-stconvert。这里我们不会详细解释每一个配置,有兴趣的同学可以自行谷歌对应的插件学习。
接下来,我们来看下analyzer
的配置,后续我们针对每个Field
实际使用的也是analyzer
中的配置
{"mall": {"settings": {"index": {..."analysis": {"filter": {...},"char_filter": {...},"analyzer": {"ik_syno": {"filter": ["my_synonym_filter"],"type": "custom","tokenizer": "ik_max_word"},"smart_syno": {"filter": ["my_synonym_filter"],"type": "custom","tokenizer": "ik_smart"},"ik_max_word_t2s": {"char_filter": ["tsconvert"],"tokenizer": "ik_max_word"},"ik_smart_t2s": {"char_filter": ["tsconvert"],"tokenizer": "ik_smart"},"origin_pinyin_firstletter": {"filter": ["origin_and_pinyin"],"tokenizer": "keyword"}}}}},"mappings": {}}
}
这里配置了5个最终的分析器
ik_syno
smart_syno
ik_max_word_t2s
ik_smart_t2s
origin_pinyin_firstletter
当然,名字也是我们自己取的,我们先来看看ik_syno
中的配置
"ik_syno": {"filter": ["my_synonym_filter"],"type": "custom","tokenizer": "ik_max_word"
}
其中,filter
为过滤器配置(笔者看来更像是修改器),这里我们就用上了上面配置好的my_synonym_filter
(如果不记得可以返回上文看看),type
表示分析器的类型,这里是custom
表示自定义类型;tokenizer
是分词器,使用的是大名鼎鼎的ik
分词器(一款针对中文的分词器,不了解的话可以看看这篇文章)
这样,ik_syno
就成为了一个能够进行细粒度中文分词,并且具有自定义同义词过滤修改的分析器。
在看另外一个ik_smart_t2s
,就是一个能够识别繁体中文,并且能够进行智能(粗粒度)分词的分析器
其他几个的组合原理基本类似,这里就不赘述了。
Field分析器应用
好了,分析器配完了,想要让他们生效,我们需要将其应用到对应的Field
上
{"mall": {"settings": {"index": {"number_of_shards": "5","number_of_replicas": "1","analysis": {"filter": {...},"char_filter": {...},"analyzer": {...}}}},"mappings": {"dynamic": "strict","properties": {//商品id"itemid": {"type": "long"},//标题"title": {"copy_to":["full_name","smart_title"],"analyzer":"ik_syno","type":"text","fields":{"pinyin":{"analyzer":"origin_pinyin_firstletter","type":"text"}}},//上新时间"pubtime": {"type": "long"},//ip名称"ipname": {"copy_to":["full_name"],"analyzer":"ik_syno","type":"text","fields":{"pinyin":{"analyzer":"origin_pinyin_firstletter","type":"text"}}},//品牌id"brandid": {"type": "integer"},//品牌名称"brandname": {"copy_to":["full_name"],"type":"keyword","fields":{"pinyin":{"analyzer":"origin_pinyin_firstletter","type":"text"}}},//后台类目id"categoryid": {"type": "long"},//前台类目id"logic_categoryid": {"type": "keyword"},//评论数"commentnum": {"type": "long"},//用户打分"qualityscore": {"type": "long"},//订阅数"subscribenum": {"type": "long"},// copy_to 字段"full_name":{"analyzer":"ik_syno","type":"text"}"smart_title":{"analyzer":"smart_syno","type":"text"}}}}
}
字段类型这类属于比较基本的,如果对ES的字段类型不熟悉,可以参考这篇文章。这里字段比较多,我们重点看看最常被用作检索的title
字段是如何配置的
"title": {"type":"text","analyzer":"ik_syno","copy_to":["full_name","smart_title"],"fields":{"pinyin":{"analyzer":"origin_pinyin_firstletter","type":"text"}}
}
可以看到,标题作为最常被检索的字段,是很有必要进行分词的,所以类型上我们将其定义为文本text
,analyzer
使用上之前配置的ik_syno
分析器。
copy_to
copy_to
是ES提供的一种用于提高检索效率,简化查询语句的功能,他可以将带有 copy_to
的字段复制到copy_to
所指定的字段上。
观察上面的字段配置,发现有很多字段被copy到了full_name
和smart_title
字段上,以full_name
为例。这样做的好处是我们在查询文档时候,不需要去指定搜索哪个字段,而是只需要去搜索full_name
就可以了,这在电商搜索中是很重要的,因为你无法判断用户搜索的是商品的名称,品牌还是类型(也许更多)。
但是这样做会引起另外一个问题,这个我们将会在下一篇文章中提到并解决。
multi-fields
我们还看到字段中配置了field
,这是出于我们需要根据不同的目的将同一个字段用不同的方式索引。这就相当于实现了 multi-fields
。例如,一个 string
类型字段可以被映射成 text
字段作为 full-text
进行搜索,同时也可以作为 keyword
字段用于排序和聚合。
除此之外,multi-fields
的另一个主要作用就是让同一字段使用不同的解析方式,使其能更好的检索。例如在本文中,我们为title
字段设置了fields: pinyin
,使其能够将不同的词语再分解成拼音,使得我们再检索过程中能够尽量更多的匹配到文档。
结语
笔者以电商索引为例,简单描述了在索引配置中用到的一些实用功能。ES在配置方面为我们提供了灵活丰富的其他功能及拓展,想要将ES的功能发挥到最大,合理的索引配置是必不可少的,笔者也期望和朋友们一起在未来继续探索和挖掘。
更新
检索篇已更新,感兴趣的小伙伴可以看看:传送门
关于电商搜索中Elasticsearch的正确使用姿势--配置篇相关推荐
- 关于电商搜索中Elasticsearch的正确使用姿势--检索篇
文章目录 前言 检索的前一步 检索 分数 sort operator 二次召回 改变权重 组合查询 归因问题(functionScore) 聚合 结语 前言 书接上文,我们为电商项目做了个性化的索引配 ...
- 京东电商搜索中的语义检索与商品排序
导读:本文将介绍京东搜索场景中的两块技术,语义检索与商品排序.在业界检索算法基础上,我们提出一系列更适用于电商场景的检索排序算法,在业务上取得了显著收益.其中的多篇论文已被 KDD/SIGIR 等收录 ...
- 多类目MoE模型在京东电商搜索中的应用
文章作者:肖茁建博士 京东 算法工程师 编辑整理:Hoh 出品平台:DataFunTalk 导读:商品搜索引擎是电商平台满足用户购物需求的一个重要系统,它根据用户输入的搜索词,返回个性化的排序列表,以 ...
- 用Elasticsearch构建电商搜索平台,一个极有代表性的基础技术架构和算法实践案例
转自:http://www.sohu.com/a/114545287_116235 电商数据系统主要类型 一个中等的电商平台,每天都要产生百万条原始数据,上亿条用户行为数据.一般来说,电商数据一般有3 ...
- 用Elasticsearch构建电商搜索平台,一个极有代表性的基础技术架构和算法实践案例(转)
转自:https://blog.csdn.net/jek123456/article/details/54562158 随着数据规模的爆炸式增长,如何从海量的历史,实时数据中快速获取有用的信息,变得越 ...
- 用Elasticsearch构建电商搜索平台(有赞)
随着互联网数据规模的爆炸式增长,如何从海量的历史,实时数据中快速获取有用的信息,变得越来越有挑战性. 电商数据系统主要类型 一个中等的电商平台,每天都要产生百万条原始数据,上亿条用户行为数据.一般来说 ...
- 用Elasticsearch构建电商搜索平台
电商数据系统主要类型 一个中等的电商平台,每天都要产生百万条原始数据,上亿条用户行为数据.一般来说,电商数据一般有3种主要类型的数据系统: 关系型数据库 ,大多数互联网公司会选用mysql作为关数据库 ...
- 电商搜索全链路(PART I)Overview
大家好,我是kaiyuan.好久没码字了,趁着五一在家整理整理,毕竟北京这疫情哪儿也别想去 虽然我们之前分享过很多 #搜索推荐广告 方面的文章,但是发现很难有一个系统的框架,无法串联成完整的链路.于是 ...
- 【原创】使用Golang的电商搜索技术架构实现
作者:黑夜路人 时间:2022年11月 一.背景: 现在搜索技术已经是非常主流的应用技术,各种优秀的索引开源软件已经很普遍了,比如 Lucene/Solr/Elasticsearch 等等主流搜索索引 ...
最新文章
- mac 制作usb启动盘_如何使用Mac制作Windows 10 USB-从Mac终端构建可启动的ISO
- 【数理知识】《数值分析》李庆扬老师-第6章-解线性方程组的迭代法
- Android 实现系统更新功能
- Wiwiz无线Web认证实现限速
- e会学中C语言课程考试答案,管理信息系统期末考试A试卷答案卷
- 路由器上的usb接口有什么用_路由器上面的USB接口有什么用途,你都知道吗?
- 兼容ie10以下版本的placeholder属性
- paip.c++ 正则表达式的应用跟普通正则表达式的区别以及特别注意点总
- 轻松几步完成cisco交换机配置全是干货!
- 视频质量评价 VMAF,为何让人又喜又忧?
- php删除文件找回,在文件管理删除的视频怎么找回?
- Ubuntu系统英文大小写CapsLock切换混乱解决方法!
- OPCode详解及汇编与反汇编原理
- Vue用图片制作Wifi动态图 制作小喇叭效果
- Appium-Get Orientation(获取定位)
- 20172319 《程序设计与数据结构》第11周学习总结
- 【逗老师带你学IT】PRTG安装教程-部署简单功能强大的监控软件
- 实时即未来,车联网项目之phoenix on hbase 即席查询【四】
- 一秒录音转文字,一键同声翻译,这两款软件简直无敌!
- lib库反编译C语言,C语言静态链接库(lib)与动态链接库(dll)