1. 前言
閑來無事,發(fā)現(xiàn)上一篇ES博客還是去年9月份寫的中文ik分詞器 pinyin 首字母 search_as_you_type 組合使用,該篇文章還挖了一個(gè)大坑沒有填,快一年了,是時(shí)候填下坑了。
2. 期望的效果
針對(duì)股票查詢這個(gè)特點(diǎn)場(chǎng)景,再結(jié)合一般使用者的搜索習(xí)慣,暫時(shí)確定如下7種期望效果。
2.1 中文名稱
2.2 全稱拼音首字母
2.3 中文簡(jiǎn)稱
2.4 簡(jiǎn)稱拼音首字母
2.5 拼音
2.6 中文+拼音
2.7 股票編號(hào)
3. 放棄search_as_you_type類型
上一篇博客Elasticsearch教程(34)中介紹了search_as_you_type類型,通過反復(fù)的實(shí)驗(yàn)驗(yàn)證,感覺search_as_you_type類型并不符合當(dāng)前的場(chǎng)景,主要是不夠靈活,對(duì)于簡(jiǎn)稱“中行”、“建行”的支持不好。所以放棄使用它了,轉(zhuǎn)而使用IK分詞器 + pinyin分詞器。
search_as_you_type類型對(duì)“建設(shè)銀行”的處理如下:
字段 | 說明 |
---|---|
name | 按照 mapping 中的配置進(jìn)行分析。 如果未配置分析器,則使用索引的默認(rèn)分詞器 |
name ._2gram | 用大小為 2 的 shingle token filter 分詞器進(jìn)行分詞 |
name ._3gram | 用大小為 3 的 shingle token filter 分詞器進(jìn)行分詞 |
name ._index_prefix | 用 edge ngram token filter 包裝上面的 name ._3gram 的分詞器 |
下面對(duì)name = "建設(shè)銀行"這個(gè)短語分析
字段 | 分析后結(jié)果 |
---|---|
name | “建” 、“設(shè)”、“銀”、“行” |
name ._2gram | “建 設(shè)”、“設(shè) 銀”、“銀 行” |
name ._3gram | “建 設(shè) 銀”、“設(shè) 銀 行” |
name ._index_prefix | “建”、"建 "、“建 設(shè)”、"建 設(shè) "、“建 設(shè) 銀” 等等 |
4. pinyin分詞器的多音字的錯(cuò)誤修改
網(wǎng)上關(guān)于pinyin分詞器的安裝和使用的博客特別多,這里我就不贅述了。但是我得說一個(gè)非常重要的問題,目前我寫博客時(shí)最新的版本8.x還是有這樣的問題。雖然GitHub上,已經(jīng)有人提出了這個(gè)Issue,但是目前還沒有修復(fù),所以我們就自己動(dòng)手手動(dòng)改改吧。
就是多音字“銀行”的“行”,pinyin分詞器會(huì)把“yin hang”錯(cuò)誤的轉(zhuǎn)成“yin xing”,當(dāng)你測(cè)試“中國銀行”時(shí)它是對(duì)的,但是“建設(shè)銀行”時(shí)就又錯(cuò)了。不信的話你自己試試看。
這個(gè)時(shí)候需要修改下圖中的jar包解壓出來
然后修改如下圖中文件polyphone.txt
,注意千萬不要一下子把"yin xing"替換成"yin hang"。
因?yàn)椤半[形”、“銀杏”這些詞的拼音就是"yin xing"。這個(gè)你需要手動(dòng)一個(gè)一個(gè)看好了改,我不確定這個(gè)問題是nlp-lang的問題還是pinyin分詞器作者改的問題,我看nlp-lang1.7的源代碼這個(gè)文件里“銀行”確實(shí)是對(duì)的"yin hang"。
改好后,再重新打成nlp-lang-1.7.jar包,替換上圖的那個(gè)nlp-lang-1.7.jar文件,然后重啟ES就行啦。
5. 配置同義詞文件和自定義字典
1 同義詞
在ES的config目錄下,新建analysis文件夾,再創(chuàng)建synonyms.txt,配置如下同義詞
建設(shè)銀行,建行
中國銀行,中行
中信證券,中信,中證
中水漁業(yè),中漁,中水
蘇州科達(dá),科達(dá)
2 自定義字典
在ik的config目錄下創(chuàng)建ext.dic文本文件,添加一些自定義的擴(kuò)展詞
修改如下的配置文件,指定擴(kuò)展字典的文件名
上面操作執(zhí)行好了后,一定要重啟ES,否則是不生效的。
6. 設(shè)計(jì)ES文檔結(jié)構(gòu)
ES的文檔設(shè)計(jì)如下,這就是一個(gè)簡(jiǎn)單的以學(xué)習(xí)為目的實(shí)驗(yàn)性設(shè)計(jì),所以設(shè)計(jì)很簡(jiǎn)陋。
- 別人博客會(huì)設(shè)計(jì)tokenizer為ik,filter為pinyin,但是我實(shí)驗(yàn)下來不是很理想(針對(duì)我的場(chǎng)景而言)
- 對(duì)于ik和pinyin我是分開的,中文+pinyin時(shí)用"name.pinyin",純中文用"name.ik"或"name"
- 對(duì)于name主字段,“analyzer”:“standard”,原因我在上篇博客解釋了,有使用的場(chǎng)景
- 對(duì)于name子字段,"keyword"特殊情況使用
- “firstLetter”,“shortName”,"shortNameFirstLetter"在代碼中我沒有用到,考慮后期優(yōu)化先加著
- 對(duì)于無需聚合和排序的keyword,加下"doc_values":false,出于性能優(yōu)化的目的
PUT pigg_stock_base
{
"settings":{
"analysis":{
"analyzer":{
"pinyin_analyzer":{
"tokenizer":"my_pinyin"
},
"ik_max_syno":{
"tokenizer":"ik_max_word",
"filter":"my_synonym"
},
"ik_smart_syno":{
"tokenizer":"ik_smart",
"filter":"my_synonym"
}
},
"tokenizer":{
"my_pinyin":{
"type":"pinyin",
"keep_first_letter":true,
"keep_separate_first_letter":true,
"keep_full_pinyin":true,
"keep_original":false,
"limit_first_letter_length":16,
"lowercase":true,
"remove_duplicated_term":true
}
},
"filter":{
"my_synonym":{
"type":"synonym",
"synonyms_path":"analysis/synonyms.txt"
}
}
}
},
"mappings":{
"properties":{
"name":{
"type":"text",
"analyzer":"standard",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256,
"doc_values":false
},
"pinyin":{
"type":"text",
"analyzer":"pinyin_analyzer"
},
"ik":{
"type":"text",
"analyzer":"ik_max_syno",
"search_analyzer":"ik_smart_syno"
}
}
},
"firstLetter":{
"type":"keyword",
"doc_values":false
},
"shortName":{
"type":"keyword",
"doc_values":false
},
"shortNameFirstLetter":{
"type":"keyword",
"doc_values":false
},
"code":{
"type":"keyword"
}
}
}
}
插入測(cè)試數(shù)據(jù)
PUT pigg_stock_base/_doc/1
{
"name": "中國銀行",
"firstLetter": "zgyh",
"shortName": ["中行"],
"shortNameFirstLetter": ["zh"],
"code": "601988"
}
PUT pigg_stock_base/_doc/2
{
"name": "中國石油",
"firstLetter": "zgsy",
"shortName": ["中石油"],
"shortNameFirstLetter": ["zsy"],
"code": "601857"
}
PUT pigg_stock_base/_doc/3
{
"name": "建設(shè)銀行",
"firstLetter": "jsyh",
"shortName": ["建行"],
"shortNameFirstLetter": ["jh"],
"code": "601939"
}
PUT pigg_stock_base/_doc/4
{
"name": "中信證券",
"firstLetter": "zxzq",
"shortName": ["中信","中證"],
"shortNameFirstLetter": ["zx","zz"],
"code": "600030"
}
PUT pigg_stock_base/_doc/5
{
"name": "中信建設(shè)",
"firstLetter": "zxjs",
"shortName": [],
"shortNameFirstLetter": [],
"code": "601066"
}
PUT pigg_stock_base/_doc/6
{
"name": "中水漁業(yè)",
"firstLetter": "zsyy",
"shortName": ["中水"],
"shortNameFirstLetter": ["zs"],
"code": "000798"
}
7. 測(cè)試查詢DSL語句
GET pigg_stock_base/_search
{
"query": {
"match": {
"name": {
"query": "中水漁業(yè)",
"operator": "and"
}
}
}
}
GET pigg_stock_base/_search
{
"query": {
"match": {
"name.pinyin": {
"query": "中國銀行",
"operator": "and"
}
}
}
}
GET pigg_stock_base/_search
{
"query": {
"match": {
"name.ik": {
"query": "建設(shè)銀行",
"operator": "and"
}
}
}
}
GET pigg_stock_base/_search
{
"query": {
"match": {
"name": {
"query": "中國銀",
"operator": "and"
}
}
}
}
GET pigg_stock_base/_search
{
"query": {
"match": {
"name.pinyin": {
"query": "中國銀",
"operator": "and"
}
}
}
}
GET pigg_stock_base/_search
{
"query": {
"match": {
"name.pinyin": {
"query": "中國yh",
"operator": "and"
}
}
}
}
GET pigg_stock_base/_search
{
"query": {
"match": {
"name.pinyin": {
"query": "中國yinh",
"operator": "and"
}
}
}
}
GET pigg_stock_base/_search
{
"query": {
"match": {
"name.pinyin": {
"query": "中國yinhang",
"operator": "and"
}
}
}
}
GET pigg_stock_base/_search
{
"query": {
"match": {
"name.pinyin": {
"query": "zgyh",
"operator": "and"
}
}
}
}
GET pigg_stock_base/_search
{
"query": {
"match": {
"name.pinyin": {
"query": "yh",
"operator": "and"
}
}
}
}
8. 代碼
對(duì)于后端代碼我就不放了,因?yàn)槭菍W(xué)習(xí)ES的代碼,有很多地方要優(yōu)化,我拼接ES查詢語句用的是之前我博客Elasticsearch教程(27) ES拼接查詢條件的工具類提到的工具,這次又加了matchAnd,主要是為了提供如下的查詢:
GET pigg_stock_base/_search
{
"query": {
"match": {
"name": {
"query": "中銀行",
"operator": "and"
}
}
}
}
前端我用的Vue3 + Element-Plus,其實(shí)今年我的學(xué)習(xí)的目標(biāo)是啥也可以不學(xué),但是一定要把Vue3學(xué)會(huì)使用。
<script lang="ts">
export default {
name: "StockBase"
}
</script>
<template>
<div class="app-container">
<el-select
filterable
remote
reserve-keyword
placeholder="中文/首字母/拼音/代碼"
:remote-method="handleSearch"
:loading="loading"
>
<el-option
v-for="item in options"
:key="item.code"
:label="item.name + '(' + item.code + ')'"
:value="item.id"
/>
</el-select>
</div>
</template>
<script setup lang="ts">
import {ref, reactive} from 'vue'
import {listStockBaseByKeyword} from '@/api/system/stockBase';
import {StockBase} from "@/types/api/system/stockBase";
const loading = ref(false);
const options = ref<StockBase[]>([])
//const dataState = reactive({});
function handleSearch(keyword: string) {
if (keyword) {
loading.value = true;
setTimeout(() => {
loading.value = false
listStockBaseByKeyword(keyword).then(({data}) => {
options.value = data
}
);
}, 200)
} else {
options.value = []
}
}
</script>
<style scoped>
</style>
9. 結(jié)語
這個(gè)功能主要是為了學(xué)習(xí)ES的分詞器的使用,后端代碼有很多優(yōu)化的地方,比如考慮用ES的異步查詢或折疊查詢collapse,所以沒有必要放后端代碼。文章來源:http://www.zghlxwxcb.cn/news/detail-406344.html
還有前端Vue3真的很重要,比Vue2添加了不少功能,光看文檔不動(dòng)手是沒有用的,只有不斷寫頁面才能真的學(xué)會(huì)前端。文章來源地址http://www.zghlxwxcb.cn/news/detail-406344.html
到了這里,關(guān)于Elasticsearch教程(35) ik中文分詞器+pinyin拼音分詞器+同義詞的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!