由 Elasticsearch 空间换时间的线上问题说开去......

2023-10-08 07:50

本文主要是介绍由 Elasticsearch 空间换时间的线上问题说开去......,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1、线上实战问题

请教一下各位朋友,关于 ngram 的 slop 影响搜索结果?

1、前置条件:

  • 商品A的SPUCodeText为:OWBB050C99JER0021001

  • 商品B的SPUCodeText为:VSA00293ABBLACKFW2022

  • 商品C的SPUCodeText为:2WHGG0VNT03HHFC99FW2022

2、现况:搜索商品A的SPUCodeText编码:OWBB050,slop设置为49-54无法查询出该商品;slop设置为55及其以上的值,才可以查询出商品A;

3、追求目标:搜索SPUCodeText任意一组4个数字及其以上的组合,即可查询出该商品?

篇幅原因,省去了 DSL 定义和查询语句。

——题目来源:死磕Elasticsearch 知识星球https://t.zsxq.com/08rmVBnhA

2、问题释义

大前提:商品码的存储类似之前咱们视频讲过的手机号的存储,传统的分词器(默认的 standard、中文的 ik_max_word 等)都无法搞定。

需要借助于 Ngram 自定义分词实现。

那么问题来了:Ngram 分词后的数据,用 match_phrase + slop 检索出现了问题,必须 slop 设置很大才可以搞定!

什么原因导致的呢?有没有更为简洁的方法?

3、Elasticsearch 空间换时间

啥叫空间换时间,拿当下世界杯的例子一看就明白。

如下解说员说的:“15人才能打赢”。15人比正常的11人远多4人,这就是多了空间,而换取了时间或结果。当然,比赛事实远非解说员所说。

667a4e1381560c16f6d1ae2ac2d47c65.png

Elasticsearch 中 Ngram 分词本质就是空间换时间的方式,以极小的粒度切分文档,空间存储激增、写入速度会受到影响,但换来了检索效率的提升!

4、精简问题后的实现

PUT /products-001
{"settings": {"max_ngram_diff": 40,"analysis": {"analyzer": {"ruishan_ngram_analyzer": {"filter": ["lowercase"],"type": "custom","tokenizer": "ruishan_ngram_tokenizer"}},"tokenizer": {"ruishan_ngram_tokenizer": {"token_chars": ["letter","digit"],"min_gram": 3,"type": "ngram","max_gram": 40}}}},"mappings": {"properties" : {"id" : {"type" : "keyword"},"sPUCodeText" : {"type" : "text","analyzer" : "ruishan_ngram_analyzer"}}}
}PUT products-001/_bulk
{"index":{"_id":1}}
{"id":1,"sPUCodeText":"OWBB050C99JER0021001"}
{"index":{"_id":2}}
{"id":2,"sPUCodeText":"VSA00293ABBLACKFW2022"}
{"index":{"_id":3}}
{"id":3,"sPUCodeText":"2WHGG0VNT03HHFC99FW2022"}GET products-001/_search
{"query": {"bool": {"must": [{"match": {"sPUCodeText": {"query": "OWBB050"}}}]}}
}

看如下结果,一个 match 就可以搞定了!

e77fa103563fd97edd7926f38b720276.png

再来,match_phrase 可以不?

4baec711ab61ada4dc679f88e3ed90d1.png

那么match_phrase 加上较大的 slop 呢?能搞定吗?!

经反复测验,需要slop 至少设置 52 才可以搞定,如下所示。

6c2707add5deaa1586c69e7db1450057.png

为什么呢?为什么是 52 呢?

5、match_phrase 短语匹配检索的本质?

通俗点说:query 部分待检索语句(如开篇:OWBB050)的分词结果要和文档(如:OWBB050C99JER0021001)中的分词结果顺序和位次完全一致才可以!

可以通过 analyzer api 查看分词结果,如下所示:

POST products-001/_analyze
{"field": "sPUCodeText","text": ["OWBB050C99JER0021001"]
}
50d00521d6629f3901e4904918bf2b3f.png

分词后的词项单元,“OWBB050”如下图左侧所示,“OWBB050C99JER0021001”如下图右侧所示。

bf9477c522f95fdff3d417421c4140bf.png

两者并不一致,这是导致无法匹配的原因,也就是有偏差!

6、match_phrase 短语检索下参数 slop 本质

一个图彻底搞明白!

ac7dc114a62b201856e11b6b4f9053f9.png

相同颜色代表:待检索词和源文档中分词结果一样的词项。

最大差值的计算方法,比如:分词后的词项“050”,在待检索词中位次为 15, 在源文档“OWBB050C99JER0021001”为67。

差了:67-15=52。

所以,slop 补齐这个最大的差值 52,就可以实现检索和数据的召回!

slop 设置为 51,就不可以!至少 52 或者52以上才可以召回数据。

217e160935d1339fbc41c8c21f0d3bee.png

7、小结

类似 Ngram 分词后,我们已经在空间层面下足了功夫!就没必要时间层面、检索层面下功夫了!

直接 match 检索必然能检索到结果!

08f0e0b5dd827833187b5e487f57e433.png

如上的写法 filter 是可以走缓存的,推荐使用。

那,有没有更快的写法呢?

f66bbd27ea3a47108d8c57826a286874.png

仔细的同学会发现,“OWBB05”都变成小写“owbb05”才可以召回数据,而直接大写直接 term 检索无法召回数据!

为什么呢?留给大家留言思考!

4253633d582fae0ea56e39e7fb9582fe.png

推荐阅读

  1. 全网首发!从 0 到 1 Elasticsearch 8.X 通关视频

  2. 重磅 | 死磕 Elasticsearch 8.X 方法论认知清单(2022年国庆更新版)

  3. 如何系统的学习 Elasticsearch ?

c7bf34ae9530cabe384d68d9dfb6406e.jpeg

更短时间更快习得更多干货!

和全球 1800+ Elastic 爱好者一起精进!

f3d638d8ca2c8d40e9edac956013ab25.gif

比同事抢先一步学习进阶干货!

这篇关于由 Elasticsearch 空间换时间的线上问题说开去......的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/163812

相关文章

ElasticSearch+Kibana通过Docker部署到Linux服务器中操作方法

《ElasticSearch+Kibana通过Docker部署到Linux服务器中操作方法》本文介绍了Elasticsearch的基本概念,包括文档和字段、索引和映射,还详细描述了如何通过Docker... 目录1、ElasticSearch概念2、ElasticSearch、Kibana和IK分词器部署

mybatis和mybatis-plus设置值为null不起作用问题及解决

《mybatis和mybatis-plus设置值为null不起作用问题及解决》Mybatis-Plus的FieldStrategy主要用于控制新增、更新和查询时对空值的处理策略,通过配置不同的策略类型... 目录MyBATis-plusFieldStrategy作用FieldStrategy类型每种策略的作

linux下多个硬盘划分到同一挂载点问题

《linux下多个硬盘划分到同一挂载点问题》在Linux系统中,将多个硬盘划分到同一挂载点需要通过逻辑卷管理(LVM)来实现,首先,需要将物理存储设备(如硬盘分区)创建为物理卷,然后,将这些物理卷组成... 目录linux下多个硬盘划分到同一挂载点需要明确的几个概念硬盘插上默认的是非lvm总结Linux下多

Python Jupyter Notebook导包报错问题及解决

《PythonJupyterNotebook导包报错问题及解决》在conda环境中安装包后,JupyterNotebook导入时出现ImportError,可能是由于包版本不对应或版本太高,解决方... 目录问题解决方法重新安装Jupyter NoteBook 更改Kernel总结问题在conda上安装了

pip install jupyterlab失败的原因问题及探索

《pipinstalljupyterlab失败的原因问题及探索》在学习Yolo模型时,尝试安装JupyterLab但遇到错误,错误提示缺少Rust和Cargo编译环境,因为pywinpty包需要它... 目录背景问题解决方案总结背景最近在学习Yolo模型,然后其中要下载jupyter(有点LSVmu像一个

解决jupyterLab打开后出现Config option `template_path`not recognized by `ExporterCollapsibleHeadings`问题

《解决jupyterLab打开后出现Configoption`template_path`notrecognizedby`ExporterCollapsibleHeadings`问题》在Ju... 目录jupyterLab打开后出现“templandroidate_path”相关问题这是 tensorflo

如何解决Pycharm编辑内容时有光标的问题

《如何解决Pycharm编辑内容时有光标的问题》文章介绍了如何在PyCharm中配置VimEmulator插件,包括检查插件是否已安装、下载插件以及安装IdeaVim插件的步骤... 目录Pycharm编辑内容时有光标1.如果Vim Emulator前面有对勾2.www.chinasem.cn如果tools工

如何利用Java获取当天的开始和结束时间

《如何利用Java获取当天的开始和结束时间》:本文主要介绍如何使用Java8的LocalDate和LocalDateTime类获取指定日期的开始和结束时间,展示了如何通过这些类进行日期和时间的处... 目录前言1. Java日期时间API概述2. 获取当天的开始和结束时间代码解析运行结果3. 总结前言在J

最长公共子序列问题的深度分析与Java实现方式

《最长公共子序列问题的深度分析与Java实现方式》本文详细介绍了最长公共子序列(LCS)问题,包括其概念、暴力解法、动态规划解法,并提供了Java代码实现,暴力解法虽然简单,但在大数据处理中效率较低,... 目录最长公共子序列问题概述问题理解与示例分析暴力解法思路与示例代码动态规划解法DP 表的构建与意义动

Java多线程父线程向子线程传值问题及解决

《Java多线程父线程向子线程传值问题及解决》文章总结了5种解决父子之间数据传递困扰的解决方案,包括ThreadLocal+TaskDecorator、UserUtils、CustomTaskDeco... 目录1 背景2 ThreadLocal+TaskDecorator3 RequestContextH