基本概念
什么是分詞?
分詞就是將一個文本轉化成為一系列的單詞的過程,也叫文本分析,在 ElasticSearch 中稱之為 Analysis。
默認是使用標准分詞。
舉例:我是中國人 --> 我/是/中國人
分詞 api
指定分詞器進行分詞
分詞測試
POST:127.0.0.1:9200/_analyze
1、英文分詞
{
"analyzer":"standard",
"text":"hello world"
}
返回值:
{
"tokens": [
{
"token": "hello",
"start_offset": 0,
"end_offset": 5,
"type": "<ALPHANUM>",
"position": 0
},
{
"token": "world",
"start_offset": 6,
"end_offset": 11,
"type": "<ALPHANUM>",
"position": 1
}
]
}
2、中文分詞
{
"analyzer": "standard",
"text": "我是中國人"
}
返回值:分為5個詞、並不合理。
{
"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
}
]
}
3、指定索引,字段分詞
POST:127.0.0.1:9200/test/_analyze
{
"analyzer": "standard",
"field": "hobby",
"text": "我是中國人"
}
中文分詞
1、釋義
中文分詞的難點在於,在漢語中沒有明顯的詞匯分界點,如在英語中,空格可以作為分隔符。如果分隔不正確就會造成歧義。
如:
我/愛/炒肉絲
我/愛/炒/肉絲
常用中文分詞器, IK、jieba、 THULAC等,推薦使用IK分詞器。
分詞地址:
https://github.com/medcl/elasticsearch-analysis-ik
2、安裝 ik 分詞器
自動安裝
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.8.1/elasticsearch-analysis-ik-7.8.1.zip
手動安裝
將下載到的 elasticsearch-analysis-ik-7.8.1. zip 解圧到 /elasticsearch/plugins/ik 目錄下
1 mkdir es/plugins/ik
2 cp elasticsearch-analysis-ik-7.8.1.zip ./es/plugins/ik
3 unzip elasticsearch-analysis-ik-7.8.1.zip
4 ./bin/elasticsearch
3、測試是否安裝成功
POST:127.0.0.1:9200/_analyze
{
"analyzer": "ik_max_word",
"text": "我是中國人"
}
返回結果:
{
"tokens": [
{
"token": "我",
"start_offset": 0,
"end_offset": 1,
"type": "CN_CHAR",
"position": 0
},
{
"token": "是",
"start_offset": 1,
"end_offset": 2,
"type": "CN_CHAR",
"position": 1
},
{
"token": "中國人",
"start_offset": 2,
"end_offset": 5,
"type": "CN_WORD",
"position": 2
},
{
"token": "中國",
"start_offset": 2,
"end_offset": 4,
"type": "CN_WORD",
"position": 3
},
{
"token": "國人",
"start_offset": 3,
"end_offset": 5,
"type": "CN_WORD",
"position": 4
}
]
}
全文搜索
1、全文搜索兩個最重要的方面:
1、相關性( Relevance )它是評價查詢與其結果間的相關程度,並根據這種相關程度對結果排名的一種能力,這種計算方式可以是TF/IDF方法、地理位置鄰近、模糊相似,或其他的某些算法。
2、分詞( Analysis )它是將文本塊轉換為有區別的、規范化的token的一個過程,目的是為了創建倒排索引以及查詢倒排索引。
2、重置索引的分詞
PUT:127.0.0.1:9200/study
{
"settings": {
"index": {
"number_of_shards": "2",
"number_of_replicas": "0"
}
},
"mappings": {
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "text"
},
"age": {
"type": "integer"
},
"mail": {
"type": "keyword"
},
"desc": {
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
3、數據添加
POST:127.0.0.1:9200/study/_doc/_bulk
{ "create": { "_index": "study","_type": "_doc", "_id": "1001" }}
{ "id": 1001,"name": "1001","age": 11,"sex": "女", "desc": "指尖輕觸玻窗,嗤嗤的響聲,驚動了脆弱的心臟,一陣陣的酸楚,像浪潮般襲來,若果這樣酸酸的痛可以代替撕心裂肺,那就讓他長久點,這樣時間會把我忘記,這樣便可躲在這里,讓那些軟弱手舞足蹈,讓那些脆弱和不堪拼命娛樂,讓那顆緊綳的心,少少松弦。" }
{ "create": { "_index": "study","_type": "_doc", "_id": "1002" }}
{ "id": 1002,"name": "1002","age": 12,"sex": "女", "desc": "曾過往,伊顏純美無暇,如玉般璀璨,許多人像發現了財富,緊抱於懷,憐香般害怕失去。那時,遇見你的是洗禮過后的悔過者,只懂憐香,而不懂惜玉,再璀璨也掩蓋不了他身上久積的灰塵,鑄造不了你,也成就不了他,於是乎,迷糊堅固了戲劇化的情誼,疼只是簡單的疼。" }
{ "create": { "_index": "study","_type": "_doc", "_id": "1003" }}
{ "id": 1003,"name": "1003","age": 13,"sex": "女", "desc": "歲月還遠,徐徐的風吹着,卻也有了幾分蕭瑟,春天,不僅有滿天飄飛的花兒,還有到處彌散着花的幽香。隨着秋韻漸漸濃郁起來,院子里的花便盛開了,整個院子里香氣四溢,溢漫着甜絲絲的味兒。金燦的花兒一串串、一撮撮,重重疊疊簇涌着點綴在茂密的綠葉之間,溫溫暖暖象極了一個個孩子的笑臉,仿佛是給這溫暖的春天注入了一道亮麗的風景。" }
{ "create": { "_index": "study","_type": "_doc", "_id": "1004" }}
{ "id": 1004,"name": "1004","age": 14,"sex": "女", "desc": "櫻花有單櫻和雙櫻,她們綻放時滿樹燦爛,清香撲鼻,單櫻白的如雪如雲,雙櫻色彩如火似霞。但是無論是單櫻還是雙櫻,她們盛開的時間都不長,二十多天的光景,開的絢麗多彩、滿樹爛漫,落得星星瓣瓣,匆匆忙忙。" }
{ "create": { "_index": "study","_type": "_doc", "_id": "1005" }}
{ "id": 1005,"name": "1005","age": 15,"sex": "女", "desc": "真正的相愛,是人在千里,卻夢魂相依;真正的相愛,是歲月流轉,卻不離不棄;真正的相愛,是彼此付出,卻無怨無悔。" }
{ "create": { "_index": "study","_type": "_doc", "_id": "1006" }}
單詞搜索
POST: 127.0.0.1:9200/study/_doc/_search
{
"query":{
"match": {
"desc": "時光"
}
}
}
過程說明
1.檢查字段類型
描述字段 desc 是一個text類型(指定了IK分詞器), 這意味着查詢字符串本身也應該被分詞。
2.分析查詢字符串.
將查詢的字符串“音樂傳入IK分詞器中,輸出的結果是單個項音樂。因為只有一個單詞項,所以match查詢執行的是單個底層term查詢。
3.查找匹配文檔。
用term查詢在倒排索引中查找“音樂”然后獲取-組包含該項的文檔。
4.為每個文檔評分。
用term查詢計算每個文檔相關度評分. score ,這是種將詞頻( term frequency ,即詞“時光"在相關文檔的 desc 字段中出現的頻率)和反向文檔頻率t inverse document frequency ,即詞“時光"在所有文檔的 desc 字段中出現的頻率) , 以及字段的長度(即字段越短相關度越高)相結合的計算方式。
多詞搜索
POST: 127.0.0.1:9200/study/_doc/_search
{
"query":{
"match": {
"desc": "時光 歲月"
}
}
}
1、operator
可以發現結果中,包含了 "時光"、 "歲月"的數據都已經被搜索到了。
可是,搜索的結果並不是我們的預期,因為我們想要的是即包含"時光",又包含"歲月"的用戶,顯然結果返回的是 或者 的關系。
在 ElasticSearch 中可以通過 operator 指定分詞之間的邏輯關系, 默認是 or, 具體如下:
POST: 127.0.0.1:9200/study/_doc/_search
{
"query": {
"match": {
"desc": {
"query": "時光 歲月",
"operator": "and"
}
}
}
}
2、最小匹配度 minimum_should_match
前面我們測試了"OR"和“AND"搜索,這是兩個極端,其實在實際場景中, 並不會選取這2個極端,更有可能是選取這種,或者說,只需要符合一定的相似度就可以查詢到數據;
match 查詢還支持 minimum_should_match 最小匹配參數,這個可以指定必須匹配的詞項數用來表示一個文檔是否相關。
我們可以將其設置為一個具體的數字,通常的做法是將其設置為一個百分數:如: 70% ;
POST: 127.0.0.1:9200/study/_doc/_search
{
"query": {
"match": {
"desc": {
"query": "時光 歲月",
"minimum_should_match": "50%"
}
}
}
}
相似度應該多少合適呢?需要在實際的需求中進行反復測試,才可以得到合理的值。
組合搜索
POST: 127.0.0.1:9200/study/_doc/_search
{
"query": {
"bool": {
"must": {
"match": {
"desc": "時光"
}
},
"must_not": {
"match": {
"desc": "日子"
}
},
"should": [
{
"match": {
"desc": "歲月"
}
}
]
}
}
}
上面搜索的意思是:
搜索結果中必須包含時光,不能包含日子,如果包含了歲月,那么他的相似度會更高。
評分的計算規則:
bool查詢會為每一個文檔計算相關度評分 _score, 在將所有匹配的 must 和 should 語句的分數 _score 求和。
最后除以 must 和 should 語句的總數。
must_not 語句不會影響評分;他的作用只是將不相關的文檔排除。
默認情況下,should 中的內容不是必須匹配的,如果查詢語句中沒有 must,那么就會至少匹配其中一個。
當然也可以通過 minimum_should_match 參數進行控制,該值可以數字。也可以是百分比。
權重 boost
有些時候,我們可能需要對某些詞增加權重來影響該條數據的評分。
搜索關鍵字為"時光 歲月", 如果包含了"日子" 權重為10,如果包含了"還遠"權重為2。
POST: 127.0.0.1:9200/study/_doc/_search
{
"query": {
"bool": {
"must": {
"match": {
"desc": {
"query": "時光 歲月",
"operator": "and"
}
}
},
"should": [
{
"match": {
"desc": {
"query": "日子",
"boost": 10
}
}
},
{
"match": {
"desc": {
"query": "還遠",
"boost": 2
}
}
}
]
}
}
}