Elasticsearch 8.X 复杂分词搞不定,怎么办?

1、实战问题

球友提问:我想停用所有纯数字的分词 ,  官网上的这个方法好像对ik分词器无效!

11d354d8a70b27a5cd71dfd87241a6e6.png

有没有什么别的方法啊,  chart gpt 说分词可以用正则匹配   但是测试好像是不行的  我的es版本是 8.5.3。

2、进一步沟通后,得到问题最精准描述

我的查询内容可能是:"北京市海淀区清华园10栋105",ik_smart 中文分词结果为:“北京市”、“海淀区”、“清华园”、“10栋”、105。

329c6198821deba882bb530ed6c4d7a4.png

用户期望:只想把分词后,是纯数字的排除掉。也就是说:期望最终分词结果为:“北京市”、“海淀区”、“清华园”、“10栋”。

更进一步说:10栋是个分词,用户期望检索分词结果:“10栋”。但是105的意义不大,用户期望分词阶段把类似“105”的纯数字分词单元去掉。

3、解决方案探讨

有没有现成分词器可以满足用户的需求呢?目前看,没有!

那怎么办?只能自定义分词器。咱们之前讲过,自定义分词器核心就如下图三部分组成。

10cd09f9856118eaa60c5dba8699a2b5.png

三部分含义如下,结合上面的图会更好理解。

部分含义
Character Filter在分词之前对原始文本进行处理,例如去除 HTML 标签,或替换特定字符。
Tokenizer定义如何将文本切分为词条或 token。例如,使用空格或标点符号将文本切分为单词。
Token Filter对 Tokenizer 输出的词条进行进一步的处理,例如转为小写、去除停用词或添加同义词。

Character Filter 和 Token Filter 的区别如下:

它俩在 Elasticsearch 中都是文本预处理的组件,但它们的处理时机和目标略有不同:

属性Character FilterToken Filter
处理时机在 Tokenizer 之前在 Tokenizer 之后
作用对象原始字符序列词条或 token
主要功能预处理文本,如去除 HTML、转换特定字符对词条进行处理,如转为小写、去除停用词、应用同义词、生成词干等
输出修改后的字符序列处理后的词条列表

本质区别:Character Filter 针对原始的字符级别进行处理,而 Token Filter 针对分词后的词项级别进行处理。

到此为止,再看用户的需求,期望分词后去掉“数字”。那也就是在分词后的 Token filter 处理为上乘方案。

Token filter 怎么处理呢?考虑数字级别统一处理的正则表达式,数字的正则为:“^[0-9]+$”。

^[0-9]+$ 可以被分解为几个部分来解读:

  • ^:这个符号表示匹配的起始位置。也就是说,匹配的内容必须从目标字符串的开头开始。

  • [0-9]:这是一个字符类。它匹配从 0 到 9 的任何一个数字字符。

  • +:这是一个量词。它表示前面的内容(在这里是 [0-9] 字符类)必须出现一次或多次。

  • $:这个符号表示匹配的结束位置。也就是说,匹配的内容必须直到目标字符串的结尾。

所以,整体上,这个正则表达式的含义是:字符串的开头到结尾之间只包含一到多个数字字符,并且没有其他任何字符。

例如:

  • "123" 符合该正则。

  • "0123" 也符合。

  • "abc"、"123a" 或 "a123" 都不符合。

一句话,该正则表达式基本达到用户的需求。

实际实现的时候我们发现,对应 filter 环节的:"pattern_replace-tokenfilter"过滤器。该过滤会实现字符级别的替换,我们可以将正则匹配的数字替换为某个字符,比如“”空格字符。

但,还没有达到要求,空格字符用户期望是剔除。这时候,我们又得考虑“”空格如何剔除。

查阅 filter 官方文档知道,有个“analysis-length-tokenfilter”的过滤器,将最小长度设置为1,就能过滤掉长度为0的空格字符。

自此,方案初步敲定。

4、敲定和初步验证解决方案

经过上述的讨论。我们分三步走战略。

  • step 0: 分词器依然选择 ik_smart,和用户需求高度一致。

  • step 1:找出数值数据,使用正则过滤 "pattern_replace filter” 实现。==> 正则表达式 ^[0-9]+$ 替换为特定的字符==> ""。

  • Step 2:  删除空格,借助 length filter 实现。==> lenth > 1 小范围验证一下:

GET /_analyze
{
  "tokenizer": "ik_smart",
  "filter": [
    {
      "type": "pattern_replace",
      "pattern": "^[0-9]+$",
      "replacement": ""
    },
    {
      "type": "length",
      "min": 1
    }
  ],
  "text": "11111111北京市10522222海淀区1053333清华园10栋105"
}

在将输入文本复杂化处理后,分词结果依然能达到预期。

64649c59d0ca2e89f443d74235166d7c.png

5、实操实现自定义分词

有了前面的初步实现,自定义分词就变得容易。

DELETE my-index-20230811-000002
PUT my-index-20230811-000002
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_custom_analyzer": {
          "tokenizer": "ik_smart",
          "filter": [
            "regex_process",
            "remove_length_lower_1"
          ]
        }
      },
      "filter": {
        "regex_process": {
          "type": "pattern_replace",
          "pattern": "^[0-9]+$",
          "replacement": ""
        },
        "remove_length_lower_1": {
          "type": "length",
          "min": 1
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "address":{
        "type":"text",
        "analyzer": "my_custom_analyzer"
      }
    }
  }
}

POST my-index-20230811-000002/_analyze
{
  "text": [
    "1111北京市3333海淀区444444清华园10栋105"
  ],
  "analyzer": "my_custom_analyzer"
}

索引定义解读如下:

部分子部分名称描述
SettingsAnalyzermy_custom_analyzer使用的分词器: ik_smart
- 使用的过滤器: regex_process, remove_length_lower_1
SettingsFilterregex_process类型: pattern_replace
匹配全数字的模式,并替换为空字符串
SettingsFilterremove_length_lower_1类型: length
确保仅保留长度大于或等于1的词条
MappingsPropertiesaddress类型: text
使用的分析器: my_custom_analyzer

上 述配置的主要目的是:创建一个自定义的analyzer,该analyzer可以处理中文文本,将纯数字的token替换为空,并确保分析结果中不包含空token。

最终结果如下,达到预期效果。

902839516fbd1e365b2abde5274c6f58.png

6、小结

当传统默认分词不能达到我们特定的、复杂的需求的时候,记得还有一招:自定义分词。

自定义分词记住三部分组成后,拆解一下复杂问题的需求,问题就会迎刃而解。

视频解读如下:

欢迎大家关注下我的视频号,不定期分享 Elasticsearch 实战进阶干货!

7、参考

https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-overview.html

https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-length-tokenfilter.html

https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-pattern_replace-tokenfilter.html

推荐阅读

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

  2. 重磅 | 死磕 Elasticsearch 8.X 方法论认知清单

  3. 如何系统的学习 Elasticsearch ?

  4. 2023,做点事

  5. Elasticsearch自定义分词,从一个问题说开去

  6. Elasticsearch 自定义分词同义词环节的这个细节不大好理解......

52d2be9902d7e0b68a3095095e183ae7.jpeg

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

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

f6a34a4c323c5139928022b198d7050d.gif

大模型时代,抢先一步学习进阶干货!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/72442.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

迪瑞克斯拉算法 — 优化

在上一篇迪瑞克斯拉算法中将功能实现了出来,完成了图集中从源点出发获取所有可达的点的最短距离的收集。 但在代码中getMinDistanceAndUnSelectNode()方法的实现并不简洁,每次获取minNode时,都需要遍历整个Map,时间复杂度太高。这…

TypeScript 语法

环境搭建 以javascript为基础构建的语言,一个js的超集,可以在任何支持js的平台中执行,ts扩展了js并且添加了类型,但是ts不能被js解析器直接执行,需要编译器编译为js文件,然后引入到 html 页面使用。 ts增…

Git Cherry-pick使用

概述 无论项目大小,当你和一群程序员一起工作时,处理多个 Git 分支之间的变更都会变得很困难。有时,与其把整个 Git 分支合并到另一个分支,不如选择并移动几个特定的提交。这个过程被称为 "挑拣", 即 Cherry-pick。 本…

使用QT纯代码创建(查找)对话框详细步骤与代码

一、创建项目文件 打开Qt Creator->文件->新建文件或项目->选择Qt Widgets Application 为项目起名字 输入类的名字 二、 了解每个文件的作用 项目创建完毕之后就会出现以下几个文件,先来分别介绍以下这些文件的作用。 Headers->finddialog.h——很显…

2023年国赛数学建模思路 - 复盘:校园消费行为分析

文章目录 0 赛题思路1 赛题背景2 分析目标3 数据说明4 数据预处理5 数据分析5.1 食堂就餐行为分析5.2 学生消费行为分析 建模资料 0 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 1 赛题背景 校园一卡通是集…

c语言每日一练(5)

前言:每日一练系列,每一期都包含5道选择题,2道编程题,博主会尽可能详细地进行讲解,令初学者也能听的清晰。每日一练系列会持续更新,暑假时三天之内必有一更,到了开学之后,将看学业情…

【三维编辑】Seal-3D:基于NeRF的交互式像素级编辑

文章目录 摘要一、引言二、方法2.1.基于nerf的编辑问题概述2.2.编辑指导生成2.3.即时预览的两阶段学生训练 三、实验四、代码总结 项目主页: https://windingwind.github.io/seal-3d/ 代码:https://github.com/windingwind/seal-3d/ 论文: https://arxiv.org/pdf/23…

k8s-----集群调度

目录 一:调度约束 二:Pod 启动创建过程 三:k8s调度过程 1、Predicate 有一系列的常见的算法 2、常见优先级选项 3、指定调度节点 (1)nodeName指定 (2)nodeSelector指定 四:亲和…

并发编程面试题2

并发编程面试题2 一、AQS高频问题: 1.1 AQS是什么? AQS就是一个抽象队列同步器,abstract queued sychronizer,本质就是一个抽象类。 AQS中有一个核心属性state,其次还有一个双向链表以及一个单项链表。 首先state…

Mac 卸载appium

安装了最新版的appium 2.0.1,使用中各种问题,卡顿....,最终决定回退的。记录下卸载的过程 1.打开终端应用程序 2.卸载全局安装的 Appium 运行以下命令以卸载全局安装的 Appium: npm uninstall -g appium 出现报错:Error: EACCES: permiss…

阿里云服务器带宽计费模式怎么选?有什么区别?

阿里云服务器公网带宽计费模式按固定带宽和按使用流量哪个划算?阿里云百科以北京地域为例,按固定带宽计费1M带宽一个月23元,按使用流量计费1GB流量0.8元,如果云服务器带宽使用率低于10%,那么首选按使用流量计费&#x…

stepin设置菜单icon的两种方式——基础积累

最近在看大佬写的stepin后台管理系统,框架是vue3antd3.xvite,下面记录一下,菜单图标的使用方法。 1.第一种方法就是使用antd中的icon图标 书写方式如下: {path: /,name: 首页,redirect: /analysis,meta: {title: 首页,renderMen…

Untiy Json和Xml的序列化和反序列化

Json的序列化和反序列化 1.定义数据类 [Serializable] public class ZoomPoint {// 点名称, 将作为Key被字典存储public string name;// 轴心X坐标public Vector2 pivot Vector2.one / 2;// 放大倍率,小于1是为缩小倍率,小于0是取绝对值,不…

redis学习笔记(九)

文章目录 python对redis基本操作(1)连接redis(2)数据类型操作 python对redis基本操作 (1)连接redis # 方式1 import redisr redis.Redis(host127.0.0.1, port6379) r.set(foo, Bar) print(r.get(foo))# …

【MOOC】北京理工大学Python网络爬虫与信息提取慕课答案-综合挑出了一些很难评的慕课测验题

1 Requests库中的get()方法最常用,下面哪个说法正确?‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬…

mysql 技术总结

一、mysql 索引(左小右大) 下图中为二叉树 mysql索引类型以及数据结构 BTREE结构 BTree又叫多路平衡搜索树,一颗m叉的BTree特性如下: 树中每个节点最多包含m个孩子。 除根节点与叶子节点外,每个节点至少有[ceil(m/2…

【LeetCode每日一题】——575.分糖果

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时间频度】九【代码实现】十【提交结果】 一【题目类别】 哈希表 二【题目难度】 简单 三【题目编号】 575.分糖果 四【题目描述】 Alice 有 n 枚糖&…

Qt5开发视频播放器

一、播放器界面UI设计 控件对象名位置(坐标点)对象名称组件名称备注Widget(0, 0, 809, 572)WidgetQWidgetlabellabelQLabel播放窗口label_2label_2QLabelvoice_controlvoice_controlQSlider音量滑动条btn_openbtn_openQPushButton打开文件按钮label_4la…

uniapp软键盘谈起遮住输入框和头部被顶起的问题解决

推荐: pages.json中配置如下可解决头部被顶起和表单被遮住的问题。 { "path": "pages/debug/protocol/tagWord", "style": { "app-plus": { "soft…

JAVA多线程和并发基础面试问答(翻译)

JAVA多线程和并发基础面试问答(翻译) java多线程面试问题 1. 进程和线程之间有什么不同? 一个进程是一个独立(self contained)的运行环境,它可以被看作一个程序或者一个应用。而线程是在进程中执行的一个任务。Java运行环境是一个包含了不同的类和程序…