ElasticSearch——手写一个ElasticSearch分词器(附源码)

news2024/10/3 0:27:24

1. 分词器插件

ElasticSearch提供了对文本内容进行分词的插件系统,对于不同的语言的文字分词器,规则一般是不一样的,而ElasticSearch提供的插件机制可以很好的集成各语种的分词器。

Elasticsearch 本身并不支持中文分词,但好在它支持编写和安装额外的分词管理插件,而开源的中文分词器 ik 就非常强大,具有20万以上的常用词库,可以满足一般的常用分词功能。

1.1 分词器插件作用

分词器的主要作用是把文本拆分成一个个最小粒度的单词,然后给ElasticSearch作为索引系统的词条使用。不同语种拆分单词规则也是不一样的,最常见的就是中文分词和英文分词。

对于同一个文本,使用不同分词器,拆分的效果也是不同的。如:"中国人民共和国"使用ik_max_word分词器会被拆分成:中国人民共和国、中华人民、中华、华人、人民共和国、人民、共和国、共和、国,而使用standard分词器则会拆分成:中、国、人、民、共、和、国。被拆分后的词就可以作为ElasticSearch的索引词条来构建索引系统,这样就可以使用部分内容进行搜索了

2. 常用分词器

2.1 分词器介绍

  • standard

    标准分词器。处理英文能力强, 会将词汇单元转换成小写形式,并去除停用词和标点符号,对于非英文按单字切分

  • whitespace

    空格分词器。 针对英文,仅去除空格,没有其他任何处理, 不支持非英文

  • simple

    针对英文,通过非字母字符分割文本信息,然后将词汇单元统一为小写形式,数字类型的字符会被去除

  • stop

    stop 的功能超越了simplestopsimple的基础上增加了去除英文中的常用单词(如 thea 等),也可以更加自己的需要设置常用单词,不支持中文

  • keyword

    Keyword把整个输入作为一个单独词汇单元,不会对文本进行任何拆分,通常是用在邮政编码、电话号码等需要全匹配的字段上

  • pattern

    查询文本会被自动当做正则表达式处理,生成一组terms关键字,然后在对Elasticsearch进行查询

  • snowball

    雪球分析器,在 standard 的基础上添加了 snowball filterLucene官方不推荐使用

  • language

    一个用于解析特殊语言文本的analyzer集合,但不包含中文

  • ik

    IK分词器是一个开源的基于java语言开发的轻量级的中文分词工具包。 采用了特有的“正向迭代最细粒度切分算法”,支持细粒度和最大词长两种切分模式。支持:英文字母、数字、中文词汇等分词处理,兼容韩文、日文字符。 同时支持用户自定义词库。 它带有两个分词器:

    • ik_max_word : 将文本做最细粒度的拆分,尽可能多的拆分出词语
    • ik_smart:做最粗粒度的拆分,已被分出的词语将不会再次被其它词语占有
  • pinyin

    通过用户输入的拼音匹配 Elasticsearch 中的中文

2.2 分词器示例

对于同一个输入,使用不同分词器的结果。

输入:栖霞站长江线14w6号断路器

2.2.1 standard

在这里插入图片描述

{
    "tokens": [
        {
            "token": "栖",
            "start_offset": 0,
            "end_offset": 1,
            "type": "<IDEOGRAPHIC>",
            "position": 0
        },
        {
            "token": "霞",
            "start_offset": 1,
            "end_offset": 2,
            "type": "<IDEOGRAPHIC>",
            "position": 1
        },
        {
            "token": "站",
            "start_offset": 2,
            "end_offset": 3,
            "type": "<IDEOGRAPHIC>",
            "position": 2
        },
        {
            "token": "长",
            "start_offset": 3,
            "end_offset": 4,
            "type": "<IDEOGRAPHIC>",
            "position": 3
        },
        {
            "token": "江",
            "start_offset": 4,
            "end_offset": 5,
            "type": "<IDEOGRAPHIC>",
            "position": 4
        },
        {
            "token": "线",
            "start_offset": 5,
            "end_offset": 6,
            "type": "<IDEOGRAPHIC>",
            "position": 5
        },
        {
            "token": "14w6",
            "start_offset": 6,
            "end_offset": 10,
            "type": "<ALPHANUM>",
            "position": 6
        },
        {
            "token": "号",
            "start_offset": 10,
            "end_offset": 11,
            "type": "<IDEOGRAPHIC>",
            "position": 7
        },
        {
            "token": "断",
            "start_offset": 11,
            "end_offset": 12,
            "type": "<IDEOGRAPHIC>",
            "position": 8
        },
        {
            "token": "路",
            "start_offset": 12,
            "end_offset": 13,
            "type": "<IDEOGRAPHIC>",
            "position": 9
        },
        {
            "token": "器",
            "start_offset": 13,
            "end_offset": 14,
            "type": "<IDEOGRAPHIC>",
            "position": 10
        }
    ]
}

2.2.2 ik

  • ik_smart

在这里插入图片描述

{
    "tokens": [
        {
            "token": "栖霞",
            "start_offset": 0,
            "end_offset": 2,
            "type": "CN_WORD",
            "position": 0
        },
        {
            "token": "站",
            "start_offset": 2,
            "end_offset": 3,
            "type": "CN_CHAR",
            "position": 1
        },
        {
            "token": "长江",
            "start_offset": 3,
            "end_offset": 5,
            "type": "CN_WORD",
            "position": 2
        },
        {
            "token": "线",
            "start_offset": 5,
            "end_offset": 6,
            "type": "CN_CHAR",
            "position": 3
        },
        {
            "token": "14w6",
            "start_offset": 6,
            "end_offset": 10,
            "type": "LETTER",
            "position": 4
        },
        {
            "token": "号",
            "start_offset": 10,
            "end_offset": 11,
            "type": "COUNT",
            "position": 5
        },
        {
            "token": "断路器",
            "start_offset": 11,
            "end_offset": 14,
            "type": "CN_WORD",
            "position": 6
        }
    ]
}
  • ik_max_word

在这里插入图片描述

{
    "tokens": [
        {
            "token": "栖霞",
            "start_offset": 0,
            "end_offset": 2,
            "type": "CN_WORD",
            "position": 0
        },
        {
            "token": "站长",
            "start_offset": 2,
            "end_offset": 4,
            "type": "CN_WORD",
            "position": 1
        },
        {
            "token": "长江",
            "start_offset": 3,
            "end_offset": 5,
            "type": "CN_WORD",
            "position": 2
        },
        {
            "token": "线",
            "start_offset": 5,
            "end_offset": 6,
            "type": "CN_CHAR",
            "position": 3
        },
        {
            "token": "14w6",
            "start_offset": 6,
            "end_offset": 10,
            "type": "LETTER",
            "position": 4
        },
        {
            "token": "14",
            "start_offset": 6,
            "end_offset": 8,
            "type": "ARABIC",
            "position": 5
        },
        {
            "token": "w",
            "start_offset": 8,
            "end_offset": 9,
            "type": "ENGLISH",
            "position": 6
        },
        {
            "token": "6",
            "start_offset": 9,
            "end_offset": 10,
            "type": "ARABIC",
            "position": 7
        },
        {
            "token": "号",
            "start_offset": 10,
            "end_offset": 11,
            "type": "COUNT",
            "position": 8
        },
        {
            "token": "断路器",
            "start_offset": 11,
            "end_offset": 14,
            "type": "CN_WORD",
            "position": 9
        },
        {
            "token": "断路",
            "start_offset": 11,
            "end_offset": 13,
            "type": "CN_WORD",
            "position": 10
        },
        {
            "token": "器",
            "start_offset": 13,
            "end_offset": 14,
            "type": "CN_CHAR",
            "position": 11
        }
    ]
}

2.2.3 pinyin

在这里插入图片描述

{
    "tokens": [
        {
            "token": "q",
            "start_offset": 0,
            "end_offset": 0,
            "type": "word",
            "position": 0
        },
        {
            "token": "qi",
            "start_offset": 0,
            "end_offset": 0,
            "type": "word",
            "position": 0
        },
        {
            "token": "栖霞站长江线14w6号断路器",
            "start_offset": 0,
            "end_offset": 0,
            "type": "word",
            "position": 0
        },
        {
            "token": "qixiazhanzhangjiangxian14w6haoduanluqi",
            "start_offset": 0,
            "end_offset": 0,
            "type": "word",
            "position": 0
        },
        {
            "token": "qxzzjx14w6hdlq",
            "start_offset": 0,
            "end_offset": 0,
            "type": "word",
            "position": 0
        },
        {
            "token": "x",
            "start_offset": 0,
            "end_offset": 0,
            "type": "word",
            "position": 1
        },
        {
            "token": "xia",
            "start_offset": 0,
            "end_offset": 0,
            "type": "word",
            "position": 1
        },
        {
            "token": "z",
            "start_offset": 0,
            "end_offset": 0,
            "type": "word",
            "position": 2
        },
        {
            "token": "zhan",
            "start_offset": 0,
            "end_offset": 0,
            "type": "word",
            "position": 2
        },
        {
            "token": "zhang",
            "start_offset": 0,
            "end_offset": 0,
            "type": "word",
            "position": 3
        },
        {
            "token": "j",
            "start_offset": 0,
            "end_offset": 0,
            "type": "word",
            "position": 4
        },
        {
            "token": "jiang",
            "start_offset": 0,
            "end_offset": 0,
            "type": "word",
            "position": 4
        },
        {
            "token": "xian",
            "start_offset": 0,
            "end_offset": 0,
            "type": "word",
            "position": 5
        },
        {
            "token": "14",
            "start_offset": 0,
            "end_offset": 0,
            "type": "word",
            "position": 6
        },
        {
            "token": "w",
            "start_offset": 0,
            "end_offset": 0,
            "type": "word",
            "position": 7
        },
        {
            "token": "6",
            "start_offset": 0,
            "end_offset": 0,
            "type": "word",
            "position": 8
        },
        {
            "token": "h",
            "start_offset": 0,
            "end_offset": 0,
            "type": "word",
            "position": 9
        },
        {
            "token": "hao",
            "start_offset": 0,
            "end_offset": 0,
            "type": "word",
            "position": 9
        },
        {
            "token": "d",
            "start_offset": 0,
            "end_offset": 0,
            "type": "word",
            "position": 10
        },
        {
            "token": "duan",
            "start_offset": 0,
            "end_offset": 0,
            "type": "word",
            "position": 10
        },
        {
            "token": "l",
            "start_offset": 0,
            "end_offset": 0,
            "type": "word",
            "position": 11
        },
        {
            "token": "lu",
            "start_offset": 0,
            "end_offset": 0,
            "type": "word",
            "position": 11
        }
    ]
}

3. 自定义分词器

对于上面三种分词器的效果,在某些场景下可能都符合要求,下面来看看为什么需要自定义分词器。

众所周知,在推荐系统中,对于拼音搜索是很有必要的,比如输入:"ls",希望返回与"ls"相关的索引词条,“零食(ls)”、“雷蛇(ls)”、“林书豪(lsh)”……,上面都是对的情况,但如果此处仅仅使用拼音分词器,可会"l"相关的索引词条也会被命中,比如"李宁(l)"、“兰蔻(l)”……,这种情况下的推荐就是不合理的。

如果使用拼音分词器,对于上面的输入"栖霞站长江线14w6号断路器",会产生出很多单个字母的索引词条,比如:"h""d""l"等。如果用户输入的查询条件"ql",根本不想看到这条”栖霞站长江线14w6号断路器“数据,但由于"l"词条被命中,所有该条数据也会被返回。

那如果避免这些单字母词条的索引生成呢?下面就自己手写一个ElasticSearch的分词器,定制化!!!

3.1 分词器原理

3.1.1 分词器插件工作流程

在这里插入图片描述

  • ElasticSearch在启动过程中会读取plugins/分词器/plugin-descriptor.properties文件
  • 读取该配置文件获取分词器插件启动类信息并进行初始化,属性classname指向的启动类
  • 分词器插件启动类必须继承AnalysisPlugin,确保ElasticSearch可以调用我们自定义的类来获取分词器对象
  • ElasticSearch调用分词进行分词时,会实例化AnalyzerProvider对象,该对象中有get()方法可以获取到我们自定义的Analyzer对象,同时内部tokenStream()方法会调用用createComponents()方法实例化我们自定义的Tokenizer对象
  • Tokenizer是自定义分词器的核心组件,核心方法有4个,如下:
    • incrementToken():用来判断分词集合列表中是否还存在没读取的词条信息,以及设置term的基础属性如:长度,起始偏移量,结束偏移量,词条等
    • reset():重置默认数据和加载自定义模型来处理用户输入的字符串数据并进行分词处理,加入到分词集合列表
    • end():设置当分词结束的偏移量信息
    • close():销毁输入流对象和自定义的数据
  • Tokenizer对象每次完成一次用户输入文本的分词过程都会进行上述4步方法调用

3.2 分词器验证

  • 安装分词器

    将打包完的分词器zip文件,拷贝放到ElasticSearch安装目录的plugins目录下,可用elasticsearch-plugin list命令查看
    在这里插入图片描述

  • 启动ElasticSearch

  • 验证分词器

在这里插入图片描述

{
    "tokens": [
        {
            "token": "栖霞",
            "start_offset": 0,
            "end_offset": 2,
            "type": "word",
            "position": 0
        },
        {
            "token": "qixia",
            "start_offset": 0,
            "end_offset": 2,
            "type": "word",
            "position": 1
        },
        {
            "token": "qx",
            "start_offset": 0,
            "end_offset": 2,
            "type": "word",
            "position": 2
        },
        {
            "token": "栖霞站长江线14w6号断路器",
            "start_offset": 1,
            "end_offset": 14,
            "type": "word",
            "position": 3
        },
        {
            "token": "qixiazhanzhangjiangxian14w6haoduanluqi",
            "start_offset": 1,
            "end_offset": 14,
            "type": "word",
            "position": 4
        },
        {
            "token": "qxzzjx14w6hdlq",
            "start_offset": 1,
            "end_offset": 14,
            "type": "word",
            "position": 5
        },
        {
            "token": "站",
            "start_offset": 2,
            "end_offset": 3,
            "type": "word",
            "position": 6
        },
        {
            "token": "长江",
            "start_offset": 3,
            "end_offset": 5,
            "type": "word",
            "position": 7
        },
        {
            "token": "zhangjiang",
            "start_offset": 3,
            "end_offset": 5,
            "type": "word",
            "position": 8
        },
        {
            "token": "zj",
            "start_offset": 3,
            "end_offset": 5,
            "type": "word",
            "position": 9
        },
        {
            "token": "线",
            "start_offset": 5,
            "end_offset": 6,
            "type": "word",
            "position": 10
        },
        {
            "token": "14w6",
            "start_offset": 6,
            "end_offset": 10,
            "type": "word",
            "position": 11
        },
        {
            "token": "号",
            "start_offset": 10,
            "end_offset": 11,
            "type": "word",
            "position": 12
        },
        {
            "token": "断路",
            "start_offset": 11,
            "end_offset": 13,
            "type": "word",
            "position": 13
        },
        {
            "token": "duanlu",
            "start_offset": 11,
            "end_offset": 13,
            "type": "word",
            "position": 14
        },
        {
            "token": "dl",
            "start_offset": 11,
            "end_offset": 13,
            "type": "word",
            "position": 15
        },
        {
            "token": "断路器",
            "start_offset": 11,
            "end_offset": 14,
            "type": "word",
            "position": 16
        },
        {
            "token": "duanluqi",
            "start_offset": 11,
            "end_offset": 14,
            "type": "word",
            "position": 17
        },
        {
            "token": "dlq",
            "start_offset": 11,
            "end_offset": 14,
            "type": "word",
            "position": 18
        }
    ]
}

3.3 源码编译

  • JDK17idea支持JDK17

在这里插入图片描述

  • luncene版本与ElasticSearch版本要求一致

在这里插入图片描述

  • ElasticSearch打包后的分词器与ElasticSearch使用版本一致

源码地址:https://gitee.com/frank_zxd/elasticsearch-search-analyzer

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python——BeautifulSoup库

下面例题基于同一个网页讲解&#xff0c;进入网页后右键查看页面源代码对应着看 文章目录前言一、BeautifulSoup库简介什么是BeautifulSoup库&#xff1f;BeautifulSoup库解析器网页爬虫解析网页的基本方法二、BeautifulSoup库的安装安装测试三、BeautifulSoup库的基本元素获取…

APS排产在线材线束行业的应用

经过数年的发展&#xff0c;我国线束行业从无到有、从小到大&#xff0c;已经具备了一定的规模&#xff0c;其生产的线束产品能够满足市场上绝大多数的需求。世界上&#xff0c;任何事物的发展都不可能一帆风顺&#xff0c;总是在矛盾中纠正自身不足&#xff0c;从而不断前进。…

关于CUDA+Torch+TorchVision+Python环境配置问题

背景知识 1、GPU的并行计算能力&#xff0c;在过去几年里恰当地满足了深度学习的需求。在训练强化学习模型时&#xff0c;为了提供更好地算力和训练时间&#xff0c;因此需要使用GPU。 2、CUDA&#xff1a;是Nvidia推出的只能用于自家GPU的并行计算框架。只有安装这个框架才能…

机器学习笔记之条件随机场(五)条件随机场需要解决的任务介绍

机器学习笔记之条件随机场——条件随机场需要解决的任务介绍引言回顾&#xff1a;条件随机场条件随机场要解决的任务引言 上一节介绍了条件随机场的建模对象——条件概率P(I∣O)\mathcal P(\mathcal I \mid \mathcal O)P(I∣O)参数形式和向量形式的表示。本节将针对条件随机场…

java多线程基础技术

1.1 进程与多线程 1、进程 程序由指令和数据组成&#xff0c;但这些指令要运行&#xff0c;数据要读写&#xff0c;就必须将指令加载至 CPU&#xff0c;数据加载至内存。在 指令运行过程中还需要用到磁盘、网络等设备。进程就是用来加载指令、管理内存、管理 IO 的 当一个程…

Mysql 数据库开发简介与选择

文章目录 前言一、为什么要使用数据库 数据库的概念为什么要使用数据库二、程序员为什么要学习数据库三、数据库的选择 主流数据库简介使用MySQL的优势版本选择四、Windows 平台下安装与配置MySQL 启动MySQL 服务控制台登录MySQL命令五、Linux 平台下安装与配置MySQL总结前言 …

【附源码】计算机毕业设计JAVA宠物收养管理

【附源码】计算机毕业设计JAVA宠物收养管理 目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; JAVA mybati…

go微服务框架Kratos简单使用总结

Kratos是B站开源的一款go的微服务框架&#xff0c;最近PS5上的 战神诸神黄昏比较火&#xff0c;主角就是奎托斯。这个框架的名字就取自他。 在进行框架选型时&#xff0c;对比了目前主流的很多go微服务框架&#xff0c;如Zero&#xff0c;最后对比之下&#xff0c;选择了Krato…

vector容器 (20221115)

一、vector容器 1、功能&#xff1a;与数组非常相似&#xff0c;也称为单端数组。 2、区别&#xff1a;数组是静态空间&#xff0c;vector可以动态扩展。 动态扩展&#xff1a;并不是在原空间之后续接新空间&#xff0c;而是找更大的内存空间&#xff0c;将原数据拷贝到新空…

Django框架的电商商城的设计与实现python语言

摘要 随着计算机技术&#xff0c;网络技术的迅猛发展&#xff0c;Internet 的不断普及&#xff0c;网络在各个领域里发挥了越来越重要的作用。特别是随着近年人民生活水平不断提高&#xff0c;电商商城给商家的业务带来了更大的发展机遇。 在经济快速发展的带动下&#xff0c;服…

网络读卡器开发,带你智能感知无线设备

随着物联网行业的快速发展&#xff0c;针对网络读卡器的技术要求也在不断地提升&#xff0c;为此出现一款体积小、低功耗、高度集成、性能稳定的非接触读卡器&#xff0c;用户不需要进行编程设计&#xff0c;只用发送简单命令&#xff0c;就能完成对卡片的读写。 网路读卡器是智…

通过DataEase行列权限设置实现数据权限管控

在企业的日常经营中&#xff0c;企业人数达到一定数量之后&#xff0c;就需要对企业的层级和部门进行细分&#xff0c;建立企业的树形组织架构。围绕着树形组织架构&#xff0c;企业能够将权限落实到个人&#xff0c;避免企业内部出现管理混乱等情况。而在涉及到数据分析等工作…

浮点数 C语言 IEEE754

知识内化&#xff1a;用自己的语言讲述一遍&#xff0c;把复杂的东西解释得简单透彻 计算机表示浮点数的问题&#xff1a;&#xff08;自己分析一下这个问题&#xff09; 输入是&#xff1a;任意一个浮点数&#xff0c;正无穷到负无穷&#xff0c;包括整数部分和小数部分 2222…

支持I2S数字音频接口;音频功放芯片NTP8835C

韩国耐福数字功放系列其NTP8835C芯片采用I2S数字输入接口&#xff0c; 可用于音频应用场合&#xff0c;例如蓝牙&#xff0f;WIFI音箱、音响设备&#xff0c;投影仪、高清电视、会议系统等。通过I2S传输数字音频信号&#xff0c; 能够还原和输出高保真高质量的音频信号。 NTP88…

阿里SQL又爆神作数据生态:MySQL复制技术与生产实践笔记

前言 在开源国产数据库崛起的今天&#xff0c;这本佳作《数据生态:MySQL复制技术与生产实践》&#xff0c;无疑将为MySQL在各行业的推广和使用做出贡献&#xff0c;这也是像我这样的从商业数据库转到开源数据库的从业者的福音。 MySQL能够成为“最流行的开源数据库”&#xf…

【数据结构】图—图的存储结构(邻接矩阵法、邻接表法、邻接多重法、十字链表法)

图的存储结构1 邻接矩阵法2 邻接表法3 十字链表法4邻接多重法1 邻接矩阵法 主要存储的是点&#xff0c;所以空间复杂度和点(v)有关 对象&#xff1a;稠密图、有向图、无向图 表示唯一、适合稠密图空间复杂度&#xff1a;O&#xff08;v^2&#xff09;无向图邻接矩阵一定是一个…

Docker环境安装OWT Server[Open WebRTC Toolkit]

Docker环境安装OWT Server[Open WebRTC Toolkit] 目录 Docker环境安装OWT ServerDocker自定义开发OWT Server wiki&#xff08;照着操作会有不注意的坑&#xff09;&#xff1a;An easy way to quickly evaluate OWT with Docker image 相关文章&#xff1a; Ubuntu环境安装OW…

Emlog评论区显示用户操作系统与浏览器信息教程

近期有不少初入Emlog的站长来咨询Emlog程序的评论区域如何实现获取到评价用户的操作系统和浏览器信息&#xff0c;其实要实现该功能也很简单&#xff0c;而且网上也有不少类是的插件。今天&#xff0c;冬镜就和大家聊聊不用插件来实现获取评论用户操作系统与浏览器信息。改造前…

软件测试 -- 进阶 3 软件测试设计

我并没有什么方法&#xff0c;只是对于一件事情很长时间很热心地去考虑罢了。-- 牛顿 1. 设计是什么&#xff1f; 设计是有目标、有计划的创造和创作活动&#xff0c;按特定需求制定解决方案。设计指把头脑中的设想/想法通过合理的规划、周密的计划、有效的方式表达出来的过程…

【C#】生成WebAPI实现简单调用本地数据库

需求&#xff1a;通过C#生成WebAPI&#xff0c;供微信小程序调用以访问本地数据库(微信小程序部分下次再说&#xff0c;今天先记录一下C#生成WebAPI相关的坑与注意点)。 数据库&#xff1a;SQL Server Web服务器&#xff1a;IIS 编程语言&#xff1a;C# IDE&#xff1a;VS20…