文章目录

  • 前言
  • 什么是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个部分,filterchar_filteranalyzerfilter,char_filter表示过滤器,analyzer为分析器(其实还有tokenizer分词器,不过这里没有配置),这三者的关系为analyzer包含filterchar_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"}}
}

可以看到,标题作为最常被检索的字段,是很有必要进行分词的,所以类型上我们将其定义为文本textanalyzer使用上之前配置的ik_syno分析器。

copy_to

copy_to是ES提供的一种用于提高检索效率,简化查询语句的功能,他可以将带有 copy_to的字段复制到copy_to所指定的字段上。

观察上面的字段配置,发现有很多字段被copy到了full_namesmart_title字段上,以full_name为例。这样做的好处是我们在查询文档时候,不需要去指定搜索哪个字段,而是只需要去搜索full_name就可以了,这在电商搜索中是很重要的,因为你无法判断用户搜索的是商品的名称,品牌还是类型(也许更多)。

但是这样做会引起另外一个问题,这个我们将会在下一篇文章中提到并解决。

multi-fields

我们还看到字段中配置了field,这是出于我们需要根据不同的目的将同一个字段用不同的方式索引。这就相当于实现了 multi-fields。例如,一个 string 类型字段可以被映射成 text 字段作为 full-text 进行搜索,同时也可以作为 keyword 字段用于排序和聚合。

除此之外,multi-fields的另一个主要作用就是让同一字段使用不同的解析方式,使其能更好的检索。例如在本文中,我们为title字段设置了fields: pinyin,使其能够将不同的词语再分解成拼音,使得我们再检索过程中能够尽量更多的匹配到文档。

结语

笔者以电商索引为例,简单描述了在索引配置中用到的一些实用功能。ES在配置方面为我们提供了灵活丰富的其他功能及拓展,想要将ES的功能发挥到最大,合理的索引配置是必不可少的,笔者也期望和朋友们一起在未来继续探索和挖掘。

更新

检索篇已更新,感兴趣的小伙伴可以看看:传送门

关于电商搜索中Elasticsearch的正确使用姿势--配置篇相关推荐

  1. 关于电商搜索中Elasticsearch的正确使用姿势--检索篇

    文章目录 前言 检索的前一步 检索 分数 sort operator 二次召回 改变权重 组合查询 归因问题(functionScore) 聚合 结语 前言 书接上文,我们为电商项目做了个性化的索引配 ...

  2. 京东电商搜索中的语义检索与商品排序

    导读:本文将介绍京东搜索场景中的两块技术,语义检索与商品排序.在业界检索算法基础上,我们提出一系列更适用于电商场景的检索排序算法,在业务上取得了显著收益.其中的多篇论文已被 KDD/SIGIR 等收录 ...

  3. 多类目MoE模型在京东电商搜索中的应用

    文章作者:肖茁建博士 京东 算法工程师 编辑整理:Hoh 出品平台:DataFunTalk 导读:商品搜索引擎是电商平台满足用户购物需求的一个重要系统,它根据用户输入的搜索词,返回个性化的排序列表,以 ...

  4. 用Elasticsearch构建电商搜索平台,一个极有代表性的基础技术架构和算法实践案例

    转自:http://www.sohu.com/a/114545287_116235 电商数据系统主要类型 一个中等的电商平台,每天都要产生百万条原始数据,上亿条用户行为数据.一般来说,电商数据一般有3 ...

  5. 用Elasticsearch构建电商搜索平台,一个极有代表性的基础技术架构和算法实践案例(转)

    转自:https://blog.csdn.net/jek123456/article/details/54562158 随着数据规模的爆炸式增长,如何从海量的历史,实时数据中快速获取有用的信息,变得越 ...

  6. 用Elasticsearch构建电商搜索平台(有赞)

    随着互联网数据规模的爆炸式增长,如何从海量的历史,实时数据中快速获取有用的信息,变得越来越有挑战性. 电商数据系统主要类型 一个中等的电商平台,每天都要产生百万条原始数据,上亿条用户行为数据.一般来说 ...

  7. 用Elasticsearch构建电商搜索平台

    电商数据系统主要类型 一个中等的电商平台,每天都要产生百万条原始数据,上亿条用户行为数据.一般来说,电商数据一般有3种主要类型的数据系统: 关系型数据库 ,大多数互联网公司会选用mysql作为关数据库 ...

  8. 电商搜索全链路(PART I)Overview

    大家好,我是kaiyuan.好久没码字了,趁着五一在家整理整理,毕竟北京这疫情哪儿也别想去 虽然我们之前分享过很多 #搜索推荐广告 方面的文章,但是发现很难有一个系统的框架,无法串联成完整的链路.于是 ...

  9. 【原创】使用Golang的电商搜索技术架构实现

    作者:黑夜路人 时间:2022年11月 一.背景: 现在搜索技术已经是非常主流的应用技术,各种优秀的索引开源软件已经很普遍了,比如 Lucene/Solr/Elasticsearch 等等主流搜索索引 ...

最新文章

  1. mac 制作usb启动盘_如何使用Mac制作Windows 10 USB-从Mac终端构建可启动的ISO
  2. 【数理知识】《数值分析》李庆扬老师-第6章-解线性方程组的迭代法
  3. Android 实现系统更新功能
  4. Wiwiz无线Web认证实现限速
  5. e会学中C语言课程考试答案,管理信息系统期末考试A试卷答案卷
  6. 路由器上的usb接口有什么用_路由器上面的USB接口有什么用途,你都知道吗?
  7. 兼容ie10以下版本的placeholder属性
  8. paip.c++ 正则表达式的应用跟普通正则表达式的区别以及特别注意点总
  9. 轻松几步完成cisco交换机配置全是干货!
  10. 视频质量评价 VMAF,为何让人又喜又忧?
  11. php删除文件找回,在文件管理删除的视频怎么找回?
  12. Ubuntu系统英文大小写CapsLock切换混乱解决方法!
  13. OPCode详解及汇编与反汇编原理
  14. Vue用图片制作Wifi动态图 制作小喇叭效果
  15. Appium-Get Orientation(获取定位)
  16. 20172319 《程序设计与数据结构》第11周学习总结
  17. 【逗老师带你学IT】PRTG安装教程-部署简单功能强大的监控软件
  18. 实时即未来,车联网项目之phoenix on hbase 即席查询【四】
  19. 一秒录音转文字,一键同声翻译,这两款软件简直无敌!
  20. lib库反编译C语言,C语言静态链接库(lib)与动态链接库(dll)

热门文章

  1. vue中实现商品购物车全选反选
  2. R-GAT实现基于方面级情感分析
  3. Windows server 2008 R2 忘记密码后重置密码
  4. 数据库幻读,到底是个什么奇葩问题?
  5. 相对定位android,android 相对定位布局方向
  6. 扁线电机结构和优劣势分析
  7. 电商系统中常见的9大坑!库存超卖、重复下单、物流单ABA...
  8. ios真机调试时需要添加的UDID是什么?怎么获取?
  9. 极客时间·3小时Python 数据分析和可视化 学习笔记
  10. 源码阅读工具 lxr 安装配置初探