Elasticsearch學(xué)習(xí)之映射與分析

映射(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"就并不相同。確切值20142014-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字段包含:

  1. The quick brown fox jumped over the lazy dog
  2. Quick brown foxes leap over lazy dogs in summer

為了創(chuàng)建倒排索引吕世,我們首先切分每個(gè)文檔的content字段為單獨(dú)的單詞(我們把它們叫做詞(terms)或者表征(tokens))(譯者注:關(guān)于termstokens的翻譯比較生硬,只需知道語句分詞后的個(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)性午磁。

但是在我們的倒排索引中還有些問題:

  1. "Quick""quick"被認(rèn)為是不同的單詞尝抖,但是用戶可能認(rèn)為它們是相同的毡们。
  2. "fox""foxes"很相似,就像"dog""dogs"——它們都是同根詞昧辽。
  3. "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)的文檔放椰。例如:

  1. "Quick"可以轉(zhuǎn)為小寫成為"quick"
  2. "foxes"可以被轉(zhuǎn)為根形式"fox"愉粤。同理"dogs"可以被轉(zhuǎn)為"dog"庄敛。
  3. "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分析器自帶一套英語停用詞庫——像andthe這些與語義無關(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)生匹配任一20140915的查詢語句斋竞,它依舊匹配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_offsetend_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ù)是indexanalyer序攘。

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扒接、doubledate等等)也接受index參數(shù)们衙,但相應(yīng)的值只能是nonot_analyzed钾怔,它們的值不能被分析。

分析

對(duì)于analyzed類型的字符串字段蒙挑,使用analyzer參數(shù)來指定哪一種分析器將在搜索和索引的時(shí)候使用宗侦。默認(rèn)的,Elasticsearch使用standard分析器矾利,但是你可以通過指定一個(gè)內(nèi)建的分析器來更改它,例如whitespace男旗、simpleenglish欣鳖。

{
    "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_nameuser_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ì)username字段的映射與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ì)象中提到它干像。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蝠筑,一起剝皮案震驚了整個(gè)濱河市什乙,隨后出現(xiàn)的幾起案子臣镣,更是在濱河造成了極大的恐慌忆某,老刑警劉巖弃舒,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件苗踪,死亡現(xiàn)場(chǎng)離奇詭異削锰,居然都是意外死亡器贩,警方通過查閱死者的電腦和手機(jī)蛹稍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門稚字,熙熙樓的掌柜王于貴愁眉苦臉地迎上來胆描,“玉大人昌讲,你說我怎么就攤上這事短绸〈妆眨” “怎么了朝卒?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵囚企,是天一觀的道長(zhǎng)瑞眼。 經(jīng)常有香客問我伤疙,道長(zhǎng),這世上最難降的妖魔是什么蛙讥? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任谬墙,我火速辦了婚禮,結(jié)果婚禮上部默,老公的妹妹穿的比我還像新娘傅蹂。我一直安慰自己份蝴,他們只是感情好婚夫,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布案糙。 她就那樣靜靜地躺著,像睡著了一般奢讨。 火紅的嫁衣襯著肌膚如雪禽笑。 梳的紋絲不亂的頭發(fā)上佳镜,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天蟀伸,我揣著相機(jī)與錄音蠢络,去河邊找鬼迟蜜。 笑死娜睛,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的方库。 我是一名探鬼主播纵潦,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼寥院!你這毒婦竟也來了只磷?” 一聲冷哼從身側(cè)響起钮追,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎苗沧,沒想到半個(gè)月后刊棕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡待逞,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年甥角,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片识樱。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡嗤无,死狀恐怖震束,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情当犯,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布恰响,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一尺碰、第九天 我趴在偏房一處隱蔽的房頂上張望固耘。 院中可真熱鬧偿枕,春花似錦墓塌、人聲如沸韩肝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間念搬,已是汗流浹背偎漫。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國打工史隆, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蚣驼,地道東北人留储。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓丐膝,卻偏偏與公主長(zhǎng)得像浑此,于是被迫代替她去往敵國和親蒲犬。 傳聞我的和親對(duì)象是個(gè)殘疾皇子沛慢,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355