在前面的章節中,我們給大家介紹了索引中的對映型別,也就是每一個欄位都有一個型別,比如:long,text,date等。這和我們的資料庫非常的相似,那麼它的不同之處是什麼呢?對了,就是全文索引,在ES當中,只有text型別的欄位才會用的全文索引,那麼這裡就會引出ES中一個非常重要的概念,文字分析器(Text analysis)。
分析器使ES支援全文索引,搜尋的結果是和你搜尋的內容相關的,而不是你搜尋內容的確切匹配。我們用ES官網中的例子給大家舉例,假如你在搜尋框中輸入的內容是Quick fox jumps
,你想得到的結果是A quick brown fox jumps over the lazy dog
,或者結果中包含這樣的詞fast fox
或foxes leap
。
分析器之所以能夠使搜尋支援全文索引,都是因為有分詞器(tokenization),它可以將一句話、一篇文章切分成不同的詞語,每個詞語都是獨立的。假如你在ES索引中新增了一條記錄the quick brown fox jumps
,而使用者搜尋時輸入的內容是quick fox
,並沒有完全匹配的內容,但是因為有了分詞器,你索引的內容被切分成了不同的、獨立的詞,使用者搜尋的內容也會進行相應的切分,所以使用者搜尋的內容雖然沒有完全匹配,但也能夠搜尋到想要的內容。
分析器除了要做分詞,還要做歸一化(Normalization)。分詞器能夠使搜尋內容在每一個詞上匹配,但這種匹配也只是在字面上進行的匹配。
- 比如你搜尋
Quick
,但是不能匹配到quick
,它們的大小寫不同。 - 比如你搜尋
fox
,但是不能匹配到foxes
,它是複數形式。 - 比如你搜尋
jumps
,不能匹配到leaps
,雖然它們是同義詞。
為了解決這些問題,分析器要把這些分詞歸一化到標準的格式。這樣我們在搜尋的時候就不用嚴格的匹配了,相似的詞語我們也能夠檢索出來,上面的3種情況,我們也能夠搜尋出相應的結果。
分析器的組成
分析器,無論是內建的,還是自定義的,都是由3部分組成:字元過濾器(character filters)、分詞器(tokenizers)、分詞過濾器(token filters)。
字元過濾器
字元過濾器接收最原始的文件,並且可以改變其內容,比如:可以把中文的一二三四五六七八九,變成阿拉伯數字123456789。它還可以過濾html標籤,並對其進行轉義。還可以通過正規表示式,把匹配到的內容轉化成其他的內容。一個分析器可以有多個字元過濾器,也可以沒有字元過濾器。
分詞器
一個分析器只能有一個確定的分詞器,它可以把一句話分成若干個詞,比如:空格分詞器。當你輸入一句話Quick brown fox!
,它將被切分成[Quick, brown, fox!]
。
分詞過濾器
分詞過濾器接收分詞並且可以改變分詞,比如:小寫分詞過濾器,它將接收到的分詞全部轉換成小寫。助詞過濾器,它將刪除掉一些公共的助詞,比如英語裡的 the
,is
,are
等,中文裡的的
,得
等。同義詞過濾器,它將在你的分詞中,新增相應的同義詞。一個分析器可以有多個分詞過濾器,它們將按順序執行。
我們在建立索引和搜尋時,都會用的分析器。
配置文字分析器
前面我們講了分析器的基本概念,也瞭解了全文搜尋的基本步驟。下面我們看一下如何配置文字分析器,ES預設給我們配置的分析器是標準分析器。如果標準的分析器不適合你,你可以指定其他的分析器,或者自定義一個分析器。
ES有分析器的api,我們指定分析器和文字內容,就可以得到分詞的結果。比如:
POST _analyze
{
"analyzer": "whitespace",
"text": "The quick brown fox."
}
返回的結果如下:
{
"tokens": [
{
"token": "The",
"start_offset": 0,
"end_offset": 3,
"type": "word",
"position": 0
},
{
"token": "quick",
"start_offset": 4,
"end_offset": 9,
"type": "word",
"position": 1
},
{
"token": "brown",
"start_offset": 10,
"end_offset": 15,
"type": "word",
"position": 2
},
{
"token": "fox.",
"start_offset": 16,
"end_offset": 20,
"type": "word",
"position": 3
}
]
}
我們指定的分析器是空格分析器,輸入的文字內容是The quick brown fox.
,返回結果是用空格切分的四個詞。我們也可以測試分析器的組合,比如:
POST _analyze
{
"tokenizer": "standard",
"filter": [ "lowercase", "asciifolding" ],
"text": "Is this déja vu?"
}
我們指定了標準的分詞器,小寫過濾器和asciifolding過濾器。輸入的內容是Is this déja vu?
,我們執行一下,得到如下的結果:
{
"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": "deja",
"start_offset": 8,
"end_offset": 12,
"type": "<ALPHANUM>",
"position": 2
},
{
"token": "vu",
"start_offset": 13,
"end_offset": 15,
"type": "<ALPHANUM>",
"position": 3
}
]
}
我們可以看到結果中,is
變成了小寫,déja
變成了deja
,最後的?
也過濾掉了。
為指定的欄位配置分析器
我們在建立對映時,可以為每一個text
型別的欄位指定分析器,例如:
PUT my_index
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "whitespace"
}
}
}
}
我們在my_index
索引中,建立了title
欄位,它的型別是text
,它的分析器是whitespace
空格分析器。
為索引指定預設的分析器
如果我們覺得為每一個欄位指定分析器過於麻煩,我們還可以為索引指定一個預設的分詞器,如下:
PUT my_index
{
"settings": {
"analysis": {
"analyzer": {
"default": {
"type": "whitespace"
}
}
}
}
}
我們為my_index
索引指定了預設的分析器whitespace
。這樣我們在建立text
型別的欄位時,就不用為其指定分析器了。
這一節給大家介紹了分析器,我們可以看到例子中都是使用的英文分析器,下一節我們一起看一下強大的中文分析器。