映射(mapping)機(jī)制用于進(jìn)行字段類型確認(rèn)商佑,將每個(gè)字段匹配為一種確定的數(shù)據(jù)類型(string
, number
, booleans
, date
等)。
分析(analysis)機(jī)制用于進(jìn)行全文文本(Full Text)的分詞莺治,以建立供搜索用的反向索引瞻凤。
映射及分析
當(dāng)在索引中處理數(shù)據(jù)時(shí)肥隆,我們注意到一些奇怪的事站绪。有些東西似乎被破壞了:
在索引中有12個(gè)tweets,只有一個(gè)包含日期2014-09-15
遂鹊,但是我們看看下面查詢中的total
hits振乏。
GET /_search?q=2014 # 12 個(gè)結(jié)果
GET /_search?q=2014-09-15 # 還是 12 個(gè)結(jié)果 !
GET /_search?q=date:2014-09-15 # 1 一個(gè)結(jié)果
GET /_search?q=date:2014 # 0 個(gè)結(jié)果 !
為什么全日期的查詢返回所有的tweets,而針對(duì)date
字段進(jìn)行年度查詢卻什么都不返回秉扑?
為什么我們的結(jié)果因查詢_all
字段(譯者注:默認(rèn)所有字段中進(jìn)行查詢)或date
字段而變得不同慧邮?
想必是因?yàn)槲覀兊臄?shù)據(jù)在_all
字段的索引方式和在date
字段的索引方式不同而導(dǎo)致。
讓我們看看Elasticsearch在對(duì)gb
索引中的tweet
類型進(jìn)行mapping(也稱之為模式定義[注:此詞有待重新定義(schema definition)])后是如何解讀我們的文檔結(jié)構(gòu):
GET /gb/_mapping/tweet
返回:
{
"gb": {
"mappings": {
"tweet": {
"properties": {
"date": {
"type": "date",
"format": "dateOptionalTime"
},
"name": {
"type": "string"
},
"tweet": {
"type": "string"
},
"user_id": {
"type": "long"
}
}
}
}
}
}
Elasticsearch為對(duì)字段類型進(jìn)行猜測(cè)舟陆,動(dòng)態(tài)生成了字段和類型的映射關(guān)系误澳。返回的信息顯示了date
字段被識(shí)別為date
類型。_all
因?yàn)槭悄J(rèn)字段所以沒有在此顯示吨娜,不過我們知道它是string
類型脓匿。
date
類型的字段和string
類型的字段的索引方式是不同的,因此導(dǎo)致查詢結(jié)果的不同宦赠,這并不會(huì)讓我們覺得驚訝陪毡。
你會(huì)期望每一種核心數(shù)據(jù)類型(strings, numbers, booleans及dates)以不同的方式進(jìn)行索引,而這點(diǎn)也是現(xiàn)實(shí):在Elasticsearch中他們是被區(qū)別對(duì)待的勾扭。
但是更大的區(qū)別在于確切值(exact values)(比如string
類型)及全文文本(full text)之間毡琉。
這兩者的區(qū)別才真的很重要 - 這是區(qū)分搜索引擎和其他數(shù)據(jù)庫的根本差異。
確切值(Exact values) vs. 全文文本(Full text)
Elasticsearch中的數(shù)據(jù)可以大致分為兩種類型:
確切值 及 全文文本妙色。
確切值是確定的桅滋,正如它的名字一樣。比如一個(gè)date或用戶ID身辨,也可以包含更多的字符串比如username或email地址丐谋。
確切值"Foo"
和"foo"
就并不相同。確切值2014
和2014-09-15
也不相同煌珊。
全文文本号俐,從另一個(gè)角度來說是文本化的數(shù)據(jù)(常常以人類的語言書寫),比如一篇推文(Twitter的文章)或郵件正文定庵。
全文文本常常被稱為非結(jié)構(gòu)化數(shù)據(jù)
吏饿,其實(shí)是一種用詞不當(dāng)?shù)姆Q謂,實(shí)際上自然語言是高度結(jié)構(gòu)化的蔬浙。
問題是自然語言的語法規(guī)則是如此的復(fù)雜猪落,計(jì)算機(jī)難以正確解析。例如這個(gè)句子:
May is fun but June bores me.
到底是說的月份還是人呢畴博?
確切值是很容易查詢的笨忌,因?yàn)榻Y(jié)果是二進(jìn)制的 -- 要么匹配,要么不匹配俱病。下面的查詢很容易以SQL表達(dá):
WHERE name = "John Smith"
AND user_id = 2
AND date > "2014-09-15"
而對(duì)于全文數(shù)據(jù)的查詢來說官疲,卻有些微妙杂曲。我們不會(huì)去詢問這篇文檔是否匹配查詢要求?
袁余。
但是,我們會(huì)詢問這篇文檔和查詢的匹配程度如何咱揍?
颖榜。換句話說,對(duì)于查詢條件煤裙,這篇文檔的相關(guān)性有多高掩完?
我們很少確切的匹配整個(gè)全文文本。我們想在全文中查詢包含查詢文本的部分硼砰。不僅如此且蓬,我們還期望搜索引擎能理解我們的意圖:
一個(gè)針對(duì)
"UK"
的查詢將返回涉及"United Kingdom"
的文檔一個(gè)針對(duì)
"jump"
的查詢同時(shí)能夠匹配"jumped"
,"jumps"
题翰,"jumping"
甚至"leap"
"johnny walker"
也能匹配"Johnnie Walker"
恶阴,"johnnie depp"
及"Johnny Depp"
"fox news hunting"
能返回有關(guān)hunting on Fox News的故事,而"fox hunting news"
也能返回關(guān)于fox hunting的新聞故事豹障。
為了方便在全文文本字段中進(jìn)行這些類型的查詢冯事,Elasticsearch首先對(duì)文本分析(analyzes),然后使用結(jié)果建立一個(gè)倒排索引血公。我們將在以下兩個(gè)章節(jié)討論倒排索引及分析過程昵仅。
倒排索引
Elasticsearch使用一種叫做倒排索引(inverted index)的結(jié)構(gòu)來做快速的全文搜索。倒排索引由在文檔中出現(xiàn)的唯一的單詞列表累魔,以及對(duì)于每個(gè)單詞在文檔中的位置組成摔笤。
例如,我們有兩個(gè)文檔垦写,每個(gè)文檔content
字段包含:
- The quick brown fox jumped over the lazy dog
- Quick brown foxes leap over lazy dogs in summer
為了創(chuàng)建倒排索引吕世,我們首先切分每個(gè)文檔的content
字段為單獨(dú)的單詞(我們把它們叫做詞(terms)或者表征(tokens))(譯者注:關(guān)于terms
和tokens
的翻譯比較生硬,只需知道語句分詞后的個(gè)體叫做這兩個(gè)梯澜。)寞冯,把所有的唯一詞放入列表并排序,結(jié)果是這個(gè)樣子的:
Term | Doc_1 | Doc_2 | |
---|---|---|---|
Quick | X | ||
The | X | ||
brown | X | X | |
dog | X | ||
dogs | X | ||
fox | X | ||
foxes | X | ||
in | X | ||
jumped | X | ||
lazy | X | X | |
leap | X | ||
over | X | X | |
quick | X | ||
summer | X | ||
the | X |
現(xiàn)在晚伙,如果我們想搜索"quick brown"
吮龄,我們只需要找到每個(gè)詞在哪個(gè)文檔中出現(xiàn)即可:
Term | Doc_1 | Doc_2 |
---|---|---|
brown | X | X |
quick | X | |
----- | ------- | ----- |
Total | 2 | 1 |
兩個(gè)文檔都匹配,但是第一個(gè)比第二個(gè)有更多的匹配項(xiàng)咆疗。
如果我們加入簡(jiǎn)單的相似度算法(similarity algorithm)漓帚,計(jì)算匹配單詞的數(shù)目,這樣我們就可以說第一個(gè)文檔比第二個(gè)匹配度更高——對(duì)于我們的查詢具有更多相關(guān)性午磁。
但是在我們的倒排索引中還有些問題:
-
"Quick"
和"quick"
被認(rèn)為是不同的單詞尝抖,但是用戶可能認(rèn)為它們是相同的毡们。 -
"fox"
和"foxes"
很相似,就像"dog"
和"dogs"
——它們都是同根詞昧辽。 -
"jumped"
和"leap"
不是同根詞衙熔,但意思相似——它們是同義詞。
上面的索引中搅荞,搜索"+Quick +fox"
不會(huì)匹配任何文檔(記住红氯,前綴+
表示單詞必須匹配到)。只有"Quick"
和"fox"
都在同一文檔中才可以匹配查詢咕痛,但是第一個(gè)文檔包含"quick fox"
且第二個(gè)文檔包含"Quick foxes"
痢甘。(譯者注:這段真啰嗦,說白了就是單復(fù)數(shù)和同義詞沒法匹配)
用戶可以合理地希望兩個(gè)文檔都能匹配查詢茉贡,我們也可以做得更好塞栅。
如果我們將詞為統(tǒng)一為標(biāo)準(zhǔn)格式,這樣就可以找到不是確切匹配查詢腔丧,但是足以相似從而可以關(guān)聯(lián)的文檔放椰。例如:
-
"Quick"
可以轉(zhuǎn)為小寫成為"quick"
。 -
"foxes"
可以被轉(zhuǎn)為根形式"fox"
愉粤。同理"dogs"
可以被轉(zhuǎn)為"dog"
庄敛。 -
"jumped"
和"leap"
同義就可以只索引為單個(gè)詞"jump"
現(xiàn)在的索引:
Term | Doc_1 | Doc_2 |
---|---|---|
brown | X | X |
dog | X | X |
fox | X | X |
in | X | |
jump | X | X |
lazy | X | X |
over | X | X |
quick | X | X |
summer | X | |
the | X | X |
但我們還未成功。我們的搜索"+Quick +fox"
依舊失敗科汗,因?yàn)?code>"Quick"的確切值已經(jīng)不在索引里藻烤,不過,如果我們使用相同的標(biāo)準(zhǔn)化規(guī)則處理查詢字符串的content
字段头滔,查詢將變成"+quick +fox"
怖亭,這樣就可以匹配到兩個(gè)文檔。
IMPORTANT
這很重要坤检。你只可以找到確實(shí)存在于索引中的詞兴猩,所以索引文本和查詢字符串都要標(biāo)準(zhǔn)化為相同的形式。
這個(gè)標(biāo)記化和標(biāo)準(zhǔn)化的過程叫做分詞(analysis)早歇。
分析和分析器
分析(analysis)是這樣一個(gè)過程:
- 首先倾芝,標(biāo)記化一個(gè)文本塊為適用于倒排索引單獨(dú)的詞(term)
- 然后標(biāo)準(zhǔn)化這些詞為標(biāo)準(zhǔn)形式,提高它們的“可搜索性”或“查全率”
這個(gè)工作是分析器(analyzer)完成的箭跳。一個(gè)分析器(analyzer)只是一個(gè)包裝用于將三個(gè)功能放到一個(gè)包里:
字符過濾器
首先字符串經(jīng)過字符過濾器(character filter)晨另,它們的工作是在標(biāo)記化前處理字符串。字符過濾器能夠去除HTML標(biāo)記谱姓,或者轉(zhuǎn)換"&"
為"and"
借尿。
分詞器
下一步,分詞器(tokenizer)被標(biāo)記化成獨(dú)立的詞。一個(gè)簡(jiǎn)單的分詞器(tokenizer)可以根據(jù)空格或逗號(hào)將單詞分開(譯者注:這個(gè)在中文中不適用)路翻。
標(biāo)記過濾
最后狈癞,每個(gè)詞都通過所有標(biāo)記過濾(token filters),它可以修改詞(例如將"Quick"
轉(zhuǎn)為小寫)茂契,去掉詞(例如停用詞像"a"
蝶桶、"and"
、"the"
等等)掉冶,或者增加詞(例如同義詞像"jump"
和"leap"
)
Elasticsearch提供很多開箱即用的字符過濾器莫瞬,分詞器和標(biāo)記過濾器。這些可以組合來創(chuàng)建自定義的分析器以應(yīng)對(duì)不同的需求郭蕉。我們將在《自定義分析器》章節(jié)詳細(xì)討論。
內(nèi)建的分析器
不過喂江,Elasticsearch還附帶了一些預(yù)裝的分析器召锈,你可以直接使用它們。下面我們列出了最重要的幾個(gè)分析器获询,來演示這個(gè)字符串分詞后的表現(xiàn)差異:
"Set the shape to semi-transparent by calling set_trans(5)"
標(biāo)準(zhǔn)分析器
標(biāo)準(zhǔn)分析器是Elasticsearch默認(rèn)使用的分析器涨岁。對(duì)于文本分析,它對(duì)于任何語言都是最佳選擇(譯者注:就是沒啥特殊需求吉嚣,對(duì)于任何一個(gè)國家的語言梢薪,這個(gè)分析器就夠用了)。它根據(jù)Unicode Consortium的定義的單詞邊界(word boundaries)來切分文本尝哆,然后去掉大部分標(biāo)點(diǎn)符號(hào)秉撇。最后,把所有詞轉(zhuǎn)為小寫秋泄。產(chǎn)生的結(jié)果為:
set, the, shape, to, semi, transparent, by, calling, set_trans, 5
簡(jiǎn)單分析器
簡(jiǎn)單分析器將非單個(gè)字母的文本切分琐馆,然后把每個(gè)詞轉(zhuǎn)為小寫。產(chǎn)生的結(jié)果為:
set, the, shape, to, semi, transparent, by, calling, set, trans
空格分析器
空格分析器依據(jù)空格切分文本恒序。它不轉(zhuǎn)換小寫瘦麸。產(chǎn)生結(jié)果為:
Set, the, shape, to, semi-transparent, by, calling, set_trans(5)
語言分析器
特定語言分析器適用于很多語言。它們能夠考慮到特定語言的特性歧胁。例如滋饲,english
分析器自帶一套英語停用詞庫——像and
或the
這些與語義無關(guān)的通用詞。這些詞被移除后喊巍,因?yàn)檎Z法規(guī)則的存在屠缭,英語單詞的主體含義依舊能被理解(譯者注:stem English words
這句不知道該如何翻譯,查了字典崭参,我理解的大概意思應(yīng)該是將英語語句比作一株植物勿她,去掉無用的枝葉,主干依舊存在阵翎,停用詞好比枝葉逢并,存在與否并不影響對(duì)這句話的理解之剧。)。
english
分析器將會(huì)產(chǎn)生以下結(jié)果:
set, shape, semi, transpar, call, set_tran, 5
注意"transparent"
砍聊、"calling"
和"set_trans"
是如何轉(zhuǎn)為詞干的背稼。
當(dāng)分析器被使用
當(dāng)我們索引(index)一個(gè)文檔,全文字段會(huì)被分析為單獨(dú)的詞來創(chuàng)建倒排索引玻蝌。不過蟹肘,當(dāng)我們?cè)谌淖侄?strong>搜索(search)時(shí),我們要讓查詢字符串經(jīng)過同樣的分析流程處理俯树,以確保這些詞在索引中存在帘腹。
全文查詢我們將在稍后討論,理解每個(gè)字段是如何定義的许饿,這樣才可以讓它們做正確的事:
- 當(dāng)你查詢全文(full text)字段烁试,查詢將使用相同的分析器來分析查詢字符串榛丢,以產(chǎn)生正確的詞列表。
- 當(dāng)你查詢一個(gè)確切值(exact value)字段,查詢將不分析查詢字符串促绵,但是你可以自己指定罢杉。
現(xiàn)在你可以明白為什么《映射和分析》的開頭會(huì)產(chǎn)生那種結(jié)果:
-
date
字段包含一個(gè)確切值:?jiǎn)为?dú)的一個(gè)詞"2014-09-15"
饱亿。 -
_all
字段是一個(gè)全文字段修己,所以分析過程將日期轉(zhuǎn)為三個(gè)詞:"2014"
、"09"
和"15"
菩浙。
當(dāng)我們?cè)?code>_all字段查詢2014
巢掺,它一個(gè)匹配到12條推文,因?yàn)檫@些推文都包含詞2014
:
GET /_search?q=2014 # 12 results
當(dāng)我們?cè)?code>_all字段中查詢2014-09-15
劲蜻,首先分析查詢字符串址遇,產(chǎn)生匹配任一詞2014
、09
或15
的查詢語句斋竞,它依舊匹配12個(gè)推文倔约,因?yàn)樗鼈兌及~2014
。
GET /_search?q=2014-09-15 # 12 results !
當(dāng)我們?cè)?code>date字段中查詢2014-09-15
坝初,它查詢一個(gè)確切的日期浸剩,然后只找到一條推文:
GET /_search?q=date:2014-09-15 # 1 result
當(dāng)我們?cè)?code>date字段中查詢2014
,沒有找到文檔鳄袍,因?yàn)闆]有文檔包含那個(gè)確切的日期:
GET /_search?q=date:2014 # 0 results !
測(cè)試分析器
尤其當(dāng)你是Elasticsearch新手時(shí)绢要,對(duì)于如何分詞以及存儲(chǔ)到索引中理解起來比較困難。為了更好的理解如何進(jìn)行拗小,你可以使用analyze
API來查看文本是如何被分析的重罪。在查詢字符串參數(shù)中指定要使用的分析器,被分析的文本做為請(qǐng)求體:
GET /_analyze
{
"analyzer":"standard",
"text":"Text to analyze"
}
結(jié)果中每個(gè)節(jié)點(diǎn)在代表一個(gè)詞:
{
"tokens": [
{
"token": "text",
"start_offset": 0,
"end_offset": 4,
"type": "<ALPHANUM>",
"position": 1
},
{
"token": "to",
"start_offset": 5,
"end_offset": 7,
"type": "<ALPHANUM>",
"position": 2
},
{
"token": "analyze",
"start_offset": 8,
"end_offset": 15,
"type": "<ALPHANUM>",
"position": 3
}
]
}
token
是一個(gè)實(shí)際被存儲(chǔ)在索引中的詞。position
指明詞在原文本中是第幾個(gè)出現(xiàn)的剿配。start_offset
和end_offset
表示詞在原文本中占據(jù)的位置搅幅。
analyze
API 對(duì)于理解Elasticsearch索引的內(nèi)在細(xì)節(jié)是個(gè)非常有用的工具,隨著內(nèi)容的推進(jìn)呼胚,我們將繼續(xù)討論它茄唐。
指定分析器
當(dāng)Elasticsearch在你的文檔中探測(cè)到一個(gè)新的字符串字段,它將自動(dòng)設(shè)置它為全文string
字段并用standard
分析器分析蝇更。
你不可能總是想要這樣做沪编。也許你想使用一個(gè)更適合這個(gè)數(shù)據(jù)的語言分析器∧昀或者蚁廓,你只想把字符串字段當(dāng)作一個(gè)普通的字段——不做任何分析,只存儲(chǔ)確切值厨幻,就像字符串類型的用戶ID或者內(nèi)部狀態(tài)字段或者標(biāo)簽相嵌。
為了達(dá)到這種效果,我們必須通過映射(mapping)人工設(shè)置這些字段克胳。
映射
為了能夠把日期字段處理成日期,把數(shù)字字段處理成數(shù)字圈匆,把字符串字段處理成全文本(Full-text)或精確的字符串值漠另,Elasticsearch需要知道每個(gè)字段里面都包含了什么類型。這些類型和字段的信息存儲(chǔ)(包含)在映射(mapping)中跃赚。
正如《數(shù)據(jù)吞吐》一節(jié)所說笆搓,索引中每個(gè)文檔都有一個(gè)類型(type)。
每個(gè)類型擁有自己的映射(mapping)或者模式定義(schema definition)纬傲。一個(gè)映射定義了字段類型满败,每個(gè)字段的數(shù)據(jù)類型,以及字段被Elasticsearch處理的方式叹括。映射還用于設(shè)置關(guān)聯(lián)到類型上的元數(shù)據(jù)算墨。
在《映射》章節(jié)我們將探討映射的細(xì)節(jié)。這節(jié)我們只是帶你入門汁雷。
核心簡(jiǎn)單字段類型
Elasticsearch支持以下簡(jiǎn)單字段類型:
類型 | 表示的數(shù)據(jù)類型 |
---|---|
String | string |
Whole number |
byte , short , integer , long
|
Floating point |
float , double
|
Boolean | boolean |
Date | date |
當(dāng)你索引一個(gè)包含新字段的文檔——一個(gè)之前沒有的字段——Elasticsearch將使用動(dòng)態(tài)映射猜測(cè)字段類型净嘀,這類型來自于JSON的基本數(shù)據(jù)類型,使用以下規(guī)則:
JSON type | Field type |
---|---|
Boolean: true or false
|
"boolean" |
Whole number: 123
|
"long" |
Floating point: 123.45
|
"double" |
String, valid date: "2014-09-15"
|
"date" |
String: "foo bar"
|
"string" |
注意
這意味著侠讯,如果你索引一個(gè)帶引號(hào)的數(shù)字——
"123"
挖藏,它將被映射為"string"
類型,而不是"long"
類型厢漩。然而膜眠,如果字段已經(jīng)被映射為"long"
類型,Elasticsearch將嘗試轉(zhuǎn)換字符串為long,并在轉(zhuǎn)換失敗時(shí)會(huì)拋出異常宵膨。
查看映射
我們可以使用_mapping
后綴來查看Elasticsearch中的映射架谎。在本章開始我們已經(jīng)找到索引gb
類型tweet
中的映射:
GET /gb/_mapping/tweet
這展示給了我們字段的映射(叫做屬性(properties)),這些映射是Elasticsearch在創(chuàng)建索引時(shí)動(dòng)態(tài)生成的:
{
"gb": {
"mappings": {
"tweet": {
"properties": {
"date": {
"type": "date",
"format": "strict_date_optional_time||epoch_millis"
},
"name": {
"type": "string"
},
"tweet": {
"type": "string"
},
"user_id": {
"type": "long"
}
}
}
}
}
}
小提示
錯(cuò)誤的映射柄驻,例如把
age
字段映射為string
類型而不是integer
類型狐树,會(huì)造成查詢結(jié)果混亂。
要檢查映射類型鸿脓,而不是假設(shè)它是正確的抑钟!
自定義字段映射
雖然大多數(shù)情況下基本數(shù)據(jù)類型已經(jīng)能夠滿足,但你也會(huì)經(jīng)常需要自定義一些特殊類型(fields)野哭,特別是字符串字段類型在塔。
自定義類型可以使你完成以下幾點(diǎn):
- 區(qū)分全文(full text)字符串字段和準(zhǔn)確字符串字段(譯者注:就是分詞與不分詞,全文的一般要分詞拨黔,準(zhǔn)確的就不需要分詞蛔溃,比如『中國』這個(gè)詞。全文會(huì)分成『中』和『國』篱蝇,但作為一個(gè)國家標(biāo)識(shí)的時(shí)候我們是不需要分詞的贺待,所以它就應(yīng)該是一個(gè)準(zhǔn)確的字符串字段)。
- 使用特定語言的分析器(譯者注:例如中文零截、英文麸塞、阿拉伯語,不同文字的斷字涧衙、斷詞方式的差異)
- 優(yōu)化部分匹配字段
- 指定自定義日期格式(譯者注:這個(gè)比較好理解,例如英文的
Feb,12,2016
和 中文的2016年2月12日
) - 以及更多
映射中最重要的字段參數(shù)是type
哪工。除了string
類型的字段,你可能很少需要映射其他的type
:
{
"number_of_clicks": {
"type": "integer"
}
}
string
類型的字段弧哎,默認(rèn)的雁比,考慮到包含全文本,它們的值在索引前要經(jīng)過分析器分析撤嫩,并且在全文搜索此字段前要把查詢語句做分析處理偎捎。
對(duì)于string
字段,兩個(gè)最重要的映射參數(shù)是index
和analyer
序攘。
index
index
參數(shù)控制字符串以何種方式被索引鸭限。它包含以下三個(gè)值當(dāng)中的一個(gè):
值 | 解釋 |
---|---|
analyzed |
首先分析這個(gè)字符串,然后索引两踏。換言之败京,以全文形式索引此字段。 |
not_analyzed |
索引這個(gè)字段梦染,使之可以被搜索赡麦,但是索引內(nèi)容和指定值一樣朴皆。不分析此字段。 |
no |
不索引這個(gè)字段泛粹。這個(gè)字段不能為搜索到遂铡。 |
string
類型字段默認(rèn)值是analyzed
。如果我們想映射字段為確切值晶姊,我們需要設(shè)置它為not_analyzed
:
{
"tag": {
"type": "string",
"index": "not_analyzed"
}
}
其他簡(jiǎn)單類型(
long
扒接、double
、date
等等)也接受index
參數(shù)们衙,但相應(yīng)的值只能是no
和not_analyzed
钾怔,它們的值不能被分析。
分析
對(duì)于analyzed
類型的字符串字段蒙挑,使用analyzer
參數(shù)來指定哪一種分析器將在搜索和索引的時(shí)候使用宗侦。默認(rèn)的,Elasticsearch使用standard
分析器矾利,但是你可以通過指定一個(gè)內(nèi)建的分析器來更改它,例如whitespace
男旗、simple
或english
欣鳖。
{
"tweet": {
"type": "string",
"analyzer": "english"
}
}
在《自定義分析器》章節(jié)我們將告訴你如何定義和使用自定義的分析器。
更新映射
你可以在第一次創(chuàng)建索引的時(shí)候指定映射的類型观堂。此外呀忧,你也可以晚些時(shí)候?yàn)樾骂愋吞砑佑成洌ɑ蛘邽橐延械念愋透掠成洌?/p>
重要
你可以向已有映射中增加字段,但你不能修改它而账。如果一個(gè)字段在映射中已經(jīng)存在,這可能意味著那個(gè)字段的數(shù)據(jù)已經(jīng)被索引泞辐。如果你改變了字段映射笔横,那已經(jīng)被索引的數(shù)據(jù)將錯(cuò)誤并且不能被正確的搜索到。
我們可以更新一個(gè)映射來增加一個(gè)新字段咐吼,但是不能把已有字段的類型那個(gè)從analyzed
改到not_analyzed
吹缔。
為了演示兩個(gè)指定的映射方法,讓我們首先刪除索引gb
:
DELETE /gb
然后創(chuàng)建一個(gè)新索引锯茄,指定tweet
字段的分析器為english
:
PUT /gb <1>
{
"mappings": {
"tweet" : {
"properties" : {
"tweet" : {
"type" : "string",
"analyzer": "english"
},
"date" : {
"type" : "date"
},
"name" : {
"type" : "string"
},
"user_id" : {
"type" : "long"
}
}
}
}
}
<1>
這將創(chuàng)建包含mappings
的索引厢塘,映射在請(qǐng)求體中指定茶没。
再后來,我們決定在tweet
的映射中增加一個(gè)新的not_analyzed
類型的文本字段晚碾,叫做tag
抓半,使用_mapping
后綴:
PUT /gb/_mapping/tweet
{
"properties" : {
"tag" : {
"type" : "string",
"index": "not_analyzed"
}
}
}
注意到我們不再需要列出所有的已經(jīng)存在的字段,因?yàn)槲覀儧]法修改他們格嘁。我們的新字段已經(jīng)被合并至存在的那個(gè)映射中笛求。
測(cè)試映射
你可以通過名字使用analyze
API測(cè)試字符串字段的映射。對(duì)比這兩個(gè)請(qǐng)求的輸出:
GET /gb/_analyze?field=tweet&text=Black-cats <1>
GET /gb/_analyze?field=tag&text=Black-cats <2>
<1>
<2>
我們想要分析的文本被放在請(qǐng)求體中糕簿。
tweet
字段產(chǎn)生兩個(gè)詞探入,"black"
和"cat"
,tag
字段產(chǎn)生單獨(dú)的一個(gè)詞"Black-cats"
。換言之冶伞,我們的映射工作正常新症。
復(fù)合核心字段類型
除了之前提到的簡(jiǎn)單的標(biāo)量類型,JSON還有null
值响禽,數(shù)組和對(duì)象徒爹,所有這些Elasticsearch都支持:
多值字段
我們想讓tag
字段包含多個(gè)字段,這非常有可能發(fā)生芋类。我們可以索引一個(gè)標(biāo)簽數(shù)組來代替單一字符串:
{ "tag": [ "search", "nosql" ]}
對(duì)于數(shù)組不需要特殊的映射隆嗅。任何一個(gè)字段可以包含零個(gè)、一個(gè)或多個(gè)值侯繁,同樣對(duì)于全文字段將被分析并產(chǎn)生多個(gè)詞胖喳。
言外之意丽焊,這意味著數(shù)組中所有值必須為同一類型技健。你不能把日期和字符竄混合雌贱。如果你創(chuàng)建一個(gè)新字段欣孤,這個(gè)字段索引了一個(gè)數(shù)組降传,Elasticsearch將使用第一個(gè)值的類型來確定這個(gè)新字段的類型婆排。
當(dāng)你從Elasticsearch中取回一個(gè)文檔,任何一個(gè)數(shù)組的順序和你索引它們的順序一致艾少。你取回的
_source
字段的順序同樣與索引它們的順序相同缚够。
然而谍椅,數(shù)組是做為多值字段被索引的雏吭,它們沒有順序杖们。在搜索階段你不能指定“第一個(gè)值”或者“最后一個(gè)值”肩狂。倒不如把數(shù)組當(dāng)作一個(gè)值集合(bag of values)
空字段
當(dāng)然數(shù)組可以是空的孝治。這等價(jià)于有零個(gè)值谈飒。事實(shí)上杭措,Lucene沒法存放null
值瓤介,所以一個(gè)null
值的字段被認(rèn)為是空字段赘那。
這四個(gè)字段將被識(shí)別為空字段而不被索引:
"empty_string": "",
"null_value": null,
"empty_array": [],
"array_with_null_value": [ null ]
多層對(duì)象
我們需要討論的最后一個(gè)自然JSON數(shù)據(jù)類型是對(duì)象(object)——在其它語言中叫做hash募舟、hashmap琢锋、dictionary 或者 associative array.
內(nèi)部對(duì)象(inner objects)經(jīng)常用于在另一個(gè)對(duì)象中嵌入一個(gè)實(shí)體或?qū)ο笪獬@缇ㄗ瑁鰹樵?code>tweet文檔中user_name
和user_id
的替代鸟悴,我們可以這樣寫:
{
"tweet": "Elasticsearch is very flexible",
"user": {
"id": "@johnsmith",
"gender": "male",
"age": 26,
"name": {
"full": "John Smith",
"first": "John",
"last": "Smith"
}
}
}
內(nèi)部對(duì)象的映射
Elasticsearch 會(huì)動(dòng)態(tài)的檢測(cè)新對(duì)象的字段细诸,并且映射它們?yōu)?object
類型震贵,將每個(gè)字段加到 properties
字段下
{
"gb": {
"tweet": { <1>
"properties": {
"tweet": { "type": "string" },
"user": { <2>
"type": "object",
"properties": {
"id": { "type": "string" },
"gender": { "type": "string" },
"age": { "type": "long" },
"name": { <3>
"type": "object",
"properties": {
"full": { "type": "string" },
"first": { "type": "string" },
"last": { "type": "string" }
}
}
}
}
}
}
}
}
<1> 根對(duì)象.
<2><3> 內(nèi)部對(duì)象.
對(duì)user
和name
字段的映射與tweet
類型自己很相似。事實(shí)上之碗,type
映射只是object
映射的一種特殊類型幽纷,我們將 object
稱為根對(duì)象友浸。它與其他對(duì)象一模一樣收恢,除非它有一些特殊的頂層字段伦意,比如 _source
, _all
等等驮肉。
內(nèi)部對(duì)象是怎樣被索引的
Lucene 并不了解內(nèi)部對(duì)象离钝。 一個(gè) Lucene 文件包含一個(gè)鍵-值對(duì)應(yīng)的扁平表單。 為了讓 Elasticsearch 可以有效的索引內(nèi)部對(duì)象慧域,將文件轉(zhuǎn)換為以下格式:
{
"tweet": [elasticsearch, flexible, very],
"user.id": [@johnsmith],
"user.gender": [male],
"user.age": [26],
"user.name.full": [john, smith],
"user.name.first": [john],
"user.name.last": [smith]
}
內(nèi)部欄位可被歸類至name吊趾,例如"first"
论泛。 為了區(qū)別兩個(gè)擁有相同名字的欄位屁奏,我們可以使用完整路徑坟瓢,例如"user.name.first"
或甚至類型
名稱加上路徑:"tweet.user.name.first"
折联。
注意: 在以上扁平化文件中诚镰,并沒有欄位叫作
user
也沒有欄位叫作user.name
清笨。 Lucene 只索引階層或簡(jiǎn)單的值抠艾,而不會(huì)索引復(fù)雜的資料結(jié)構(gòu)。
對(duì)象-數(shù)組
內(nèi)部對(duì)象數(shù)組
最后蛙酪,一個(gè)包含內(nèi)部對(duì)象的數(shù)組如何索引滤否。 我們有個(gè)數(shù)組如下所示:
{
"followers": [
{ "age": 35, "name": "Mary White"},
{ "age": 26, "name": "Alex Jones"},
{ "age": 19, "name": "Lisa Smith"}
]
}
此文件會(huì)如我們以上所說的被扁平化藐俺,但其結(jié)果會(huì)像如此:
{
"followers.age": [19, 26, 35],
"followers.name": [alex, jones, lisa, smith, mary, white]
}
{age: 35}
與{name: Mary White}
之間的關(guān)聯(lián)會(huì)消失,因每個(gè)多值的欄位會(huì)變成一個(gè)值集合卿啡,而非有序的陣列颈娜。 這讓我們可以知道:
- 是否有26歲的追隨者官辽?
但我們無法取得準(zhǔn)確的資料如:
- 是否有26歲的追隨者且名字叫Alex Jones同仆?
關(guān)聯(lián)內(nèi)部對(duì)象可解決此類問題俗批,我們稱之為嵌套對(duì)象岁忘,我們之後會(huì)在嵌套對(duì)象中提到它干像。