在全文搜索(Fulltext Search)中,詞(Term)是一個搜索單元,表示文本中的一個詞,標(biāo)記(Token)表示在文本字段中出現(xiàn)的詞,由詞的文本、在原始文本中的開始和結(jié)束偏移量、以及數(shù)據(jù)類型等組成。ElasticSearch 把文檔數(shù)據(jù)寫到倒排索引(Inverted Index)的結(jié)構(gòu)中,倒排索引建立詞(Term)和文檔之間的映射,索引中的數(shù)據(jù)是面向詞,而不是面向文檔的。分析器(Analyzer)的作用就是分析(Analyse),用于把傳入Lucene的文檔數(shù)據(jù)轉(zhuǎn)化為倒排索引,把文本處理成可被搜索的詞。
在ElasticSearch引擎中,分析器的任務(wù)是分析(Analyze)文本數(shù)據(jù),分析是分詞,規(guī)范化文本的意思,其工作流程是:
首先,字符過濾器對分析(analyzed)文本進行過濾和處理,例如從原始文本中移除HTML標(biāo)記,根據(jù)字符映射替換文本等,
過濾之后的文本被分詞器接收,分詞器把文本分割成標(biāo)記流,也就是一個接一個的標(biāo)記,
然后,標(biāo)記過濾器對標(biāo)記流進行過濾處理,例如,移除停用詞,把詞轉(zhuǎn)換成其詞干形式,把詞轉(zhuǎn)換成其同義詞等,
最終,過濾之后的標(biāo)記流被存儲在倒排索引中;
ElasticSearch引擎在收到用戶的查詢請求時,會使用分析器對查詢條件進行分析,根據(jù)分析的結(jié)構(gòu),重新構(gòu)造查詢,以搜索倒排索引,完成全文搜索請求。
無論是內(nèi)置的分析器(analyzer),還是自定義的分析器(analyzer),都由三種構(gòu)件塊組成的:**character filters ,tokenizers **和 token filters。
-
**character filters **
字符過濾器以字符流的形式接收原始文本,并可以通過添加、刪除或更改字符來轉(zhuǎn)換該流。
舉例來說,一個字符過濾器可以用來把阿拉伯?dāng)?shù)字(??????????)轉(zhuǎn)成成Arabic-Latin的等價物(0123456789)。
一個分析器可能有0個或多個字符過濾器,它們按順序應(yīng)用。
-
Tokenizer (分詞器)
一個分詞器接收一個字符流,并將其拆分成單個token (通常是單個單詞),并輸出一個token流。例如,一個whitespace分詞器當(dāng)它看到空白的時候就會將文本拆分成token。它會將文本“Quick brown fox!”轉(zhuǎn)換為[Quick, brown, fox!]
(PS:Tokenizer 負責(zé)將文本拆分成單個token ,這里token就指的就是一個一個的單詞。就是一段文本被分割成好幾部分 )
分詞器還負責(zé)記錄每個term的順序或位置,以及該term所表示的原單詞的開始和結(jié)束字符偏移量。(PS:文本被分詞后的輸出是一個term數(shù)組)
一個分析器必須只能有一個分詞器
-
Token filters (token過濾器)
token過濾器接收token流,并且可能會添加、刪除或更改tokens。
例如,一個lowercase token filter可以將所有的token轉(zhuǎn)成小寫。stop token filter可以刪除常用的單詞,比如 the 。synonym token filter可以將同義詞引入token流。
不允許token過濾器更改每個token的位置或字符偏移量。
一個分析器可能有0個或多個token過濾器,它們按順序應(yīng)用。
ES內(nèi)置分詞器(Tokenizer)
分詞器在字符過濾器之后工作,用于把文本分割成多個標(biāo)記(Token),一個標(biāo)記基本上是詞加上一些額外信息,分詞器的處理結(jié)果是標(biāo)記流,它是一個接一個的標(biāo)記,準備被過濾器處理。
-
標(biāo)準分析器(Standard)
分析器類型是standard,由標(biāo)準分詞器(Standard Tokenizer),標(biāo)準標(biāo)記過濾器(Standard Token Filter),小寫標(biāo)記過濾器(Lower Case Token Filter)和停用詞標(biāo)記過濾器(Stopwords Token Filter)組成。參數(shù)stopwords用于初始化停用詞列表,默認是空的。
-
簡單分析器(Simple)
分析器類型是simple,實際上是小寫標(biāo)記分詞器(Lower Case Tokenizer),在非字母位置上分割文本,并把分詞轉(zhuǎn)換為小寫形式,功能上是Letter Tokenizer和 Lower Case Token Filter的結(jié)合(Combination),但是性能更高,一次性完成兩個任務(wù)。
-
空格分析器(Whitespace)
分析器類型是whitespace,實際上是空格分詞器(Whitespace Tokenizer)。
-
停用詞分析器(Stopwords)
分析器類型是stop,由小寫分詞器(Lower Case Tokenizer)和停用詞標(biāo)記過濾器(Stop Token Filter)構(gòu)成,配置參數(shù)stopwords或 stopwords_path指定停用詞列表。
-
雪球分析器(Snowball)
分析器類型是snowball,由標(biāo)準分詞器(Standard Tokenizer),標(biāo)準過濾器(Standard Filter),小寫過濾器(Lowercase Filter),停用詞過濾器(Stop Filter)和雪球過濾器(Snowball Filter)構(gòu)成。參數(shù)language用于指定語言。
-
自定義分析器
分析器類型是custom,允許用戶定制分析器。參數(shù)tokenizer 用于指定分詞器,filter用于指定過濾器,char_filter用于指定字符過濾器。
內(nèi)置分析器實例
這里我們使用的工具是Kibana,我們在這里來操作一下Elasticsearch。如下的事例是ES默認的標(biāo)準分析器,我們使用_analyze來調(diào)試實驗一下。
POST _analyze
{
"analyzer": "standard",
"text": "I am Chinese."
}
輸出如下結(jié)果:
{
"tokens" : [
{
"token" : "i",
"start_offset" : 0,
"end_offset" : 1,
"type" : "<ALPHANUM>",
"position" : 0
},
{
"token" : "am",
"start_offset" : 2,
"end_offset" : 4,
"type" : "<ALPHANUM>",
"position" : 1
},
{
"token" : "chinese",
"start_offset" : 5,
"end_offset" : 12,
"type" : "<ALPHANUM>",
"position" : 2
}
]
}
而使用空格分析器的話,就會對每個空格進行分割,如下
POST _analyze
{
"analyzer": "whitespace",
"text": "I'm Chinese."
}
輸出結(jié)果:
{
"tokens" : [
{
"token" : "I'm",
"start_offset" : 0,
"end_offset" : 3,
"type" : "word",
"position" : 0
},
{
"token" : "Chinese.",
"start_offset" : 4,
"end_offset" : 12,
"type" : "word",
"position" : 1
}
]
}
接下來我們創(chuàng)建一個自定義分析器:
# 創(chuàng)建一個自定義分詞器
PUT test_index_1
{
"settings": {
"analysis": {
"analyzer": {
"my_custom_anaylzer" : {
"type" : "custom",
"tokenizer" : "standard",
"char_filter" : ["html_strip"],
"filter" : ["lowercase"]
}
}
}
}
}
以上代碼是創(chuàng)建一個自定義分析器,其中使用分析器是標(biāo)準分析器,字符串過濾使用的是html_strip(去除里面的html標(biāo)簽內(nèi)容),token過濾器用的是lowercase,也就是把取出來的字符都轉(zhuǎn)成小寫。運行如下事例。
POST test_index_1/_analyze
{
"analyzer" : "my_custom_anaylzer",
"text" : "Is this <b> a box <b>?"
}
輸出結(jié)果為:
{
"tokens" : [
{
"token" : "is",
"start_offset" : 0,
"end_offset" : 2,
"type" : "<ALPHANUM>",
"position" : 0
},
{
"token" : "this",
"start_offset" : 3,
"end_offset" : 7,
"type" : "<ALPHANUM>",
"position" : 1
},
{
"token" : "a",
"start_offset" : 12,
"end_offset" : 13,
"type" : "<ALPHANUM>",
"position" : 2
},
{
"token" : "box",
"start_offset" : 14,
"end_offset" : 17,
"type" : "<ALPHANUM>",
"position" : 3
}
]
}
參考
https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis.html
https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-tokenfilters.html