如何提升elasticsearch中文搜索能力(自己动手训练ik中文词典)

1,181 阅读3分钟

如何提升elasticsearch中文搜索能力(自己动手训练ik中文词典)

选择一个好用的中文分词器

ElasticSearch 中文分词器对比

补充:
1.medcl/elasticsearch-analysis-ik github.com/medcl/elast…
优点:

被使用量远超过其它中文分词器几个数量级别,插件更新快能跟上elasticsearch更新

缺点:

但是词典过时比较严重,缺少新词识别的能力

2.jieba/nlp

sing1ee/elasticsearch-jieba-plugin

KennFalcon/elasticsearch-analysis-hanlp

优点:

具有发现新词能力,python版本jieba,能开启PaddlePaddle(百度飞桨)模式,使用深度学习方式进行分词,elasticsearch版本插件是否支持开启Paddle模式未知。

hanlp应该是目前中文自然语言分析能力最强的开源项目

缺点:

插件非官方支持,更新比较慢,被使用次数少.
截止2021-12-24,elasticsearch已经更新到7.16,hanlp elasticsearch 插件目前最高只支持到7.10

jieba需要自己改适配版本重新编译,看了下jieba的词典库也比较老

本人目前使用的elasticsearch 版本为7.15,因此决定继续使用ik分词器,但是要对ik分词能力弱的问题进行提升。 方案:使用python版jieba/hanlp和手上中文内容,手动训练额外中文词典,作为对ik的补充

自定义Ik分词器词典

下载 第三方词典 作为ik 分词补充

《现代汉语词典》(第7版)
CNMan/XDHYCD7th
github.com/pwxcoo/chin…

中华新华字典数据库
pwxcoo/chinese-xinhua
github.com/pwxcoo/chin…

自己训练词典提升ik能力(jieba版本)

1.下载jieba分词,安装百度飞桨模式插件

github.com/fxsjy/jieba

2.下载IK已有的词库

github.com/medcl/elast…

3.下载最新中文停用词表

github.com/xiyusullos/…

4.选择提取新词用的数据源(中文语料库)

网上很多

5.代码

# encoding=utf-8
import jieba
import json
import re

def stopwordslist():
    stopwords_file = '../../app/Services/stopwords.txt'
    stopwords = [line.strip() for line in open(stopwords_file,encoding='UTF-8').readlines()]
    return stopwords

def ikwordslist():
    stopwords_file = './ik.txt'
    stopwords = [line.strip() for line in open(stopwords_file,encoding='UTF-8').readlines()]
    return stopwords


stopwords = stopwordslist()
ikwords = ikwordslist()
total_word = []


filename = 'titles.txt'
current = 0
print("开始进行分词")

count = len(open(filename,'r').readlines())


with open(filename,'r') as f:
    for line in f.readlines():
        linestr = line.strip()
        # data = json.loads(linestr)
        seg_list = list(jieba.cut(linestr))

        # ret = [ i for i in seg_list if i not in stopwords ]

        current+=1
        if current%1000 == 0:
            print("{}/{}".format(current,count))

        seg_list =  list(set(seg_list))
        for word in seg_list:
            match = re.match(u"^[\u4e00-\u9fa5]*$", word )
            if match:
                total_word.append(word)

total_word =  list(set(total_word))

print("过滤停用词")
ret = [ i for i in total_word if i not in stopwords ]
print("过滤IK分词器已有词典")
ret2 = [ i for i in ret if i not in ikwords ]

ret2.sort()

with open ("it_cn_words.txt", "w") as thefile:
    thefile.write("\n".join(ret2))

6.设置elastcisearh ik分词额外词典

github.com/medcl/elast… 详见ik插件文档

7.重启/测试

使用原生ik词典ik_smart测试:

GET _analyze
{
  "analyzer": "ik_smart",
  "text": ["中国科学院计算所如何在html中引入javaScript代码"]
}

分词结果

中国科学院,计算所,如,何在,html,中,引入,javascript,代码

后总结: jieba paddle模式不理想,分词时候对受到空格和特殊符号影响很大,分词结果有点莫名其妙 如:

每日一博 | 一文搞懂SaaS困境、API经济与Serverless WebAssembly
正常模式:
['每日', '一博', ' ', '|', ' ', '一文', '搞懂', 'SaaS', '困境', '、', 'API', '经济', '与', 'Serverless', ' ', 'WebAssembly']
飞桨模式:
['每日', '一博 | 一文搞懂SaaS困境、API经济与Serverless WebAssembly']

jieba 默认模式效果也有点过头 也会发现很多莫名其妙新词,例如

中三大
中不为
中不写
中不出
中不受
中不含
中不太
中不常
中不随
中与子

To be continue

结巴新词发现功能过头的原因,应该和新词发现时候对于词性的判断不ok, 下载尝试,带有词性识别和中文nlp能力的hanlp,看看效果如何