前言
通過前面章節(jié)的學習,我們已經(jīng)可以讓elasticsearch對中文分詞有比較好的效果了闻蛀,就是使用IK分詞器匪傍,但我們也知道,elasticsearch的默認分詞器是standard分詞器觉痛,那如何把standard分詞器切換到IK分詞器呢役衡?
我們在講解elasticsearch的重要概念的時候我們提到了一個概念:type(類型),為了更好的理解該概念薪棒,我們還拿了關系型數(shù)據(jù)庫的表來跟type對比手蝎,因為他們不管是思想上還是概念上都是很相似的。
在使用關系型數(shù)據(jù)庫時俐芯,我們是必須事先確定好數(shù)據(jù)表結構(schema)棵介,給該表中的每個字段規(guī)定其存儲的數(shù)據(jù)類型和數(shù)據(jù)長度,是否能為空等等的約束泼各,確定好后才能創(chuàng)建該表鞍时。但是大家回想之前我們在學RESTful API的時候,我們很簡單的就完成了一個文檔的新增操作了PUT /store/employee/1
扣蜻,并沒有事先規(guī)定好類似關系型數(shù)據(jù)庫表的約束逆巍,那么既然elasticsearch中的type跟表很相似,為什么我們新增一個文檔的時候莽使,就可以直接就錄入文檔呢锐极?其實并不是沒有事先規(guī)定約束的,我們當時還補充了錄入這個文檔的執(zhí)行過程:先查找名字叫store的索引(index)芳肌,如果沒有灵再,則創(chuàng)建該索引。然后查找名字叫employee的文檔類型(type)亿笤,如果沒有翎迁,則創(chuàng)建該文檔類型。最后查找id為1的員工净薛,如果沒有則相當于新建一個員工文檔汪榔,并設置員工id為1,如果有肃拜,則相當于更新員工id為1的文檔數(shù)據(jù)痴腌。這里的文檔字段類型由elasticsearch幫我們完成自動匹配雌团,當然我們也可以自定義文檔的各個字段內(nèi)容的數(shù)據(jù)類型和其他的一些約束。當時我們是這樣說的士聪,所以锦援,并不是沒有規(guī)定好約束,而是如果我們沒有指定它的約束的話剥悟,elasticsearch就自動為我們創(chuàng)建好約束了灵寺。
在elasticsearch中,這些約束有個專業(yè)術語懦胞,叫做mapping(映射)替久,類似關系型數(shù)據(jù)庫的schema。那這樣我們就明白了我們想要使用IK分詞器來給我們的中文文檔分詞躏尉,就需要自己來給類型的字段指定映射蚯根,這些映射應該包含字段的數(shù)據(jù)類型、數(shù)據(jù)長度胀糜、使用分詞器等等的約束颅拦。那接下來我們來學習一下elasticsearch的類型映射。
類型映射詳解
查看文檔類型映射
我們可以使用elasticsearch查看類型的API來查看指定文檔的類型:
GET /索引名/_mapping/類型名
通過該API得出的結果教藻,我們可以得到以下的信息:索引距帅、映射、類型括堤、字段碌秸,在字段下,又有各種給該字段做約束的信息悄窃,所有的信息組合起來讥电,就是我們所說的類型映射了(mapping)。employee的這些類型映射我們之前并沒有給它設置轧抗,是elasticsearch自動判斷我們的數(shù)據(jù)類型恩敌,并給這些數(shù)據(jù)類型設置默認的映射,那這各個字段分別代表什么意思呢横媚?這就是我們接下來要學習的內(nèi)容了纠炮。
字段數(shù)據(jù)類型
我們先來看看elasticsearch對文檔的數(shù)據(jù)做了哪些類型的區(qū)分:
- 字符串類型:string(3.x后改成了text類型)
- 整數(shù) : byte,short灯蝴,integer恢口,long
- 浮點數(shù):float,double
- 布爾型: boolean
- 日期: date
接著我們來看看這些數(shù)據(jù)類型有什么約束條件穷躁。
約束條件
- type:指定該字段的數(shù)據(jù)類型耕肩,值為上述列出的“字段數(shù)據(jù)類型”,不指定的話,由elasticsearch自動判斷看疗。
- index:指定該字段是否索引,接收值為true和false睦授,字符串類型默認為true两芳,其他的數(shù)據(jù)類型默認為false。值為true的話會做分詞去枷。值為false的話不分詞怖辆,原樣寫入索引中。
- ignore_above:接受整數(shù)值删顶,如果字符串長度長于這個值竖螃,則不寫入索引,不指定的話默認為0逗余。
- analyzer:如果該字段需要索引的話特咆,指定索引時使用的分詞器,不指定的話默認使用標準分詞器分詞录粱。
- search_analyzer:指定搜索時使用的分詞器腻格,不知道的話使用標準分詞器分詞。
- store:值為yes和no啥繁,默認為no菜职。指定是否將該字段的原始文檔寫入索引。在elasticsearch中旗闽,因為_source中(_source下面解析)已經(jīng)存儲了一份原始文檔酬核,在索引中再存儲原始文檔就多余了,所以Elasticsearch默認是把store屬性設置為no适室。
- include_in_all:指定該字段是否需要包含在_all中(_all下面解析)嫡意,接收值為true和false,默認為flase亭病。
- null_value:如果該字段的值為null鹅很,則用該值代替。
- format:格式化日期類型罪帖,比如:yyyy-MM-dd HH:mm:ss||yyyy-MM-dd促煮。默認strict_date_optional_time||epoch_millis
元數(shù)據(jù)類型
每一個文檔都有與之關聯(lián)的元數(shù)據(jù),元數(shù)據(jù)字段是為了保證系統(tǒng)正常運行內(nèi)置字段整袁,比如_index表示索引字段菠齿,_type表示類型,_id表示文檔主鍵坐昙,這些字段都是以下劃線開始的绳匀,除了這些元數(shù)據(jù)之外,還有兩個很重要的元數(shù)據(jù),它們是_all和_source疾棵,這兩個元數(shù)據(jù)字段可以在我們創(chuàng)建類型映射的時候戈钢,指定約束條件,我們接著來看看:
- _source:存儲的文檔的原始值是尔。默認_source字段是開啟的殉了,也可以關閉,在什么情況下可以關閉呢拟枚?比如某個字段內(nèi)容非常多薪铜,業(yè)務里面只需要能對該字段進行搜索,最后返回文檔id恩溅,查看文檔詳細內(nèi)容是用id再次到mysql或者hbase中取數(shù)據(jù)隔箍,把大字段的內(nèi)容存在Elasticsearch中只會增大索引,如果一條文檔節(jié)省幾KB脚乡,放大到億萬級的量結果也是非逞烟玻可觀的。
如果想要關閉_source字段奶稠,在mapping中的設置如下:
{
"yourtype":{
"_source":{
"enabled":false
},
"properties": {
...
}
}
}
如果只想存儲某幾個字段的原始值到elasticsearch帮掉,可以通過incudes參數(shù)來設置,在mapping中的設置如下:
{
"yourtype":{
"_source":{
"includes":["field1","field2"]
},
"properties": {
...
}
}
}
同樣窒典,可以通過excludes參數(shù)排除某些字段:
{
"yourtype":{
"_source":{
"excludes":["field1","field2"]
},
"properties": {
...
}
}
}
- _all:包含全部內(nèi)容的字段蟆炊,默認是關閉的,如果要開啟_all字段瀑志,索引增大是不言而喻的涩搓。_all字段開啟適用于不指定搜索某一個字段,根據(jù)關鍵詞劈猪,搜索整個文檔內(nèi)容昧甘。
開啟_all字段的方法和_source類似,mapping中的配置如下:
{
"yourtype": {
"_all": {
"enabled": true
},
"properties": {
...
}
}
}
也可以通過在字段中指定某個字段是否包含在_all中:
{
"yourtype": {
"properties": {
"field1": {
"type": "string",
"include_in_all": false
},
"field2": {
"type": "string",
"include_in_all": true
}
}
}
}
最后,我們可以通過一張分析圖來看看_all和_source在elasticsearch中起到的作用:
那到現(xiàn)在充边,我們已經(jīng)把類型映射的數(shù)據(jù)類型、約束條件和元數(shù)據(jù)指定都了解了常侦,接下來我們就可以對之前創(chuàng)建的employee類型指定約束條件了浇冰。
創(chuàng)建類型映射(mapping)
自定義employee類型映射
那接下來我們就要給employee類型做映射了,但是由于之前employee已經(jīng)有一個elasticsearch創(chuàng)建的默認映射聋亡,而elasticsearch沒有提供類似修改類型映射的功能肘习,所以我們只能先把整個index刪除掉,然后在新建一個index坡倔,并且在添加文檔前做好employee類型映射漂佩。
注意:一般來說index是不能隨便刪除的脖含,如果真的需要刪除,那就要先備份數(shù)據(jù)投蝉,因為我們現(xiàn)在的數(shù)據(jù)都是測試數(shù)據(jù)养葵,所以就不備份了,后面我們再來講講elasticsearch的數(shù)據(jù)備份操作
1瘩缆、刪除index
先把原先的store索引刪除掉港柜,使用以下DSL語法:
DELETE http://ip:port/my_index
看到acknowledged為true,說明刪除成功咳榜!
2、創(chuàng)建index
重新創(chuàng)建store索引爽锥,使用以下DSL語法:
PUT http://ip:port/my_index
看到上圖右邊的窗口打印信息說明索引創(chuàng)建成功涌韩!
3、創(chuàng)建類型映射
創(chuàng)建employee類型映射氯夷,使用以下DSL語法:
PUT http://ip:port/my_index/my_type/_mapping
{
"my_type": {
"properties": {
"my_field1": {
"type": "text",
"index":"true",
"analyzer":"ik_max_word",
"search_analyzer":"ik_max_word"
},
"my_field2": {
...
},
...
}
}
}
語法解析:對my_index這個索引中的my_type文檔類型創(chuàng)建一個自定義mapping映射臣樱,properties塊就是my_type文檔類型的字段。其中以my_field1這個字段舉例腮考,該字段的數(shù)據(jù)類型為“text”雇毫,index為需要分詞,索引使用的分詞組件為IK分詞器踩蔚,并且是最大分詞棚放,搜索同樣使用IK分詞器,并且是最大分詞馅闽,其他沒有指定的約束飘蚯,使用默認的值。
看到acknowledged為true的答應信息說明我們的employee文檔類型約束已經(jīng)創(chuàng)建好了福也,我給該文檔類型3個字段做了約束局骤,分別是name、age和about暴凑,其中name和about都是是text數(shù)據(jù)類型峦甩,需要分詞,索引和搜索都使用ik_max_word分詞现喳,age是integer數(shù)據(jù)類型凯傲,不需要分詞。
我們再使用查看類型映射的API測試一下嗦篱,看看剛剛創(chuàng)建的類型映射是否生效:
那通過我們上述的請求發(fā)現(xiàn)泣洞,我們的employee類型映射已經(jīng)生效了,已經(jīng)不是之前那個elasticsearch給我們創(chuàng)建的默認映射了默色。
添加文檔
接下來我們在新的employee類型映射下添加文檔:
我從新添加了一份id為1的employee文檔球凰,但是我這份文檔有4個字段狮腿,name、age呕诉、about和intersect缘厢,其中name、age和about是做了映射的甩挫,intersect沒有做映射贴硫,那么elasticsearch就會自動判斷intersect字段的數(shù)據(jù)類型,并且給他設置一些默認的約束伊者。我們可以再來查看一下employee的類型映射有沒有發(fā)生什么變化:
通過上述查看employee類型映射我們發(fā)現(xiàn)英遭,它此時多了intersect字段的映射,而且約束條件都是默認的亦渗,說明如果我們添加的文檔某些字段沒有事先做映射挖诸,那么elasticsearch會為我們這些字段創(chuàng)建映射。
搜索
根據(jù)我們前面章節(jié)的學習法精,我們知道在添加文檔的時候多律,首先需要對文檔進行索引,索引的第一個環(huán)節(jié)就是對文檔分詞搂蜓,而我們剛剛已經(jīng)在類型映射中狼荞,指定了文檔分詞的組件使用IK中文分詞了,并且重新添加了文檔帮碰,那這樣的話相味,現(xiàn)在索引庫中保存的詞元就不再是一個一個的中文字符了,而是有語義的中文詞語殉挽,最后我們來搜索效果攻走。
先來看看搜索一個沒有意義的字符:
我們可以看到,搜索“中”字符已經(jīng)不會出來結果了此再,因為“中”字符單獨存在沒有什么意義昔搂,那接下來我們搜索“中國”看看:
搜索“中國”能出來結果,并且我們通過高亮顯示可以知道输拇,它是匹配到“中國”這個詞元的摘符。
那到現(xiàn)在,我們就通過這個章節(jié)的學習策吠,了解了elasticsearch的數(shù)據(jù)類型逛裤、字段約束條件和類型映射這幾個知識點了,并且通過自定義的類型映射來實現(xiàn)了中文語義搜索猴抹。