6000+字講透ElasticSearch 索引設(shè)計(jì)
ElasticSearch 索引設(shè)計(jì)
在MySQL中數(shù)據(jù)庫(kù)設(shè)計(jì)非常重要,同樣在ES中數(shù)據(jù)庫(kù)設(shè)計(jì)也是非常重要的
概述
我們創(chuàng)建索引就像創(chuàng)建表結(jié)構(gòu)一樣,必須非常慎重的,索引如果創(chuàng)建不好后面會(huì)出現(xiàn)各種各樣的問(wèn)題
索引設(shè)計(jì)的重要性
索引創(chuàng)建后,索引的分片只能通過(guò)_split和_shrink接口對(duì)其進(jìn)行成倍的增加和縮減
主要是因?yàn)閑s的數(shù)據(jù)是通過(guò)_routing分配到各個(gè)分片上面的,所以本質(zhì)上是不推薦去改變索引的分片數(shù)量的,因?yàn)檫@樣都會(huì)對(duì)數(shù)據(jù)進(jìn)行重新的移動(dòng)。
還有就是索引只能新增字段,不能對(duì)字段進(jìn)行修改和刪除,缺乏靈活性,所以每次都只能通過(guò)_reindex重建索引了,還有就是一個(gè)分片的大小以及所以分片數(shù)量的多少嚴(yán)重影響到了索引的查詢和寫入性能,所以可想而知,設(shè)計(jì)一個(gè)好的索引能夠減少后期的運(yùn)維管理和提高不少性能,所以前期對(duì)索引的設(shè)計(jì)是相當(dāng)?shù)闹匾摹?br>
基于時(shí)間的Index設(shè)計(jì)
Index設(shè)計(jì)時(shí)要考慮的第一件事,就是基于時(shí)間對(duì)Index進(jìn)行分割,即每隔一段時(shí)間產(chǎn)生一個(gè)新的Index
這樣設(shè)計(jì)的目的
因?yàn)楝F(xiàn)實(shí)世界的數(shù)據(jù)是隨著時(shí)間的變化而不斷產(chǎn)生的,切分管理可以獲得足夠的靈活性和更好的性能
如果數(shù)據(jù)都存儲(chǔ)在一個(gè)Index中,很難進(jìn)行擴(kuò)展和調(diào)整,因?yàn)镋lasticsearch中Index的某些設(shè)置在創(chuàng)建時(shí)就設(shè)定好了,是不能更改的,比如Primary Shard的個(gè)數(shù)。
而根據(jù)時(shí)間來(lái)切分Index,則可以實(shí)現(xiàn)一定的靈活性,既可以在數(shù)據(jù)量過(guò)大時(shí)及時(shí)調(diào)整Shard個(gè)數(shù),也可以及時(shí)響應(yīng)新的業(yè)務(wù)需求。
大多數(shù)業(yè)務(wù)場(chǎng)景下,客戶對(duì)數(shù)據(jù)的請(qǐng)求都會(huì)命中在最近一段時(shí)間上,通過(guò)切分Index,可以盡可能的避免掃描不必要的數(shù)據(jù),提高性能。
時(shí)間間隔
根據(jù)上面的分析,自然是時(shí)間越短越能保持靈活性,但是這樣做就會(huì)導(dǎo)致產(chǎn)生大量的Index,而每個(gè)Index都會(huì)消耗資源來(lái)維護(hù)其元信息的,因此需要在靈活性、資源和性能上做權(quán)衡
常見(jiàn)的間隔有小時(shí)、天、周和月:先考慮總共要存儲(chǔ)多久的數(shù)據(jù),然后選一個(gè)既不會(huì)產(chǎn)生大量Index又能夠滿足一定靈活性的間隔,比如你需要存儲(chǔ)6個(gè)月的數(shù)據(jù),那么一開(kāi)始選擇“周”這個(gè)間隔就會(huì)比較合適。
考慮業(yè)務(wù)增長(zhǎng)速度:假如業(yè)務(wù)增長(zhǎng)的特別快,比如上周產(chǎn)生了1億數(shù)據(jù),這周就增長(zhǎng)到了10億,那么就需要調(diào)低這個(gè)間隔來(lái)保證有足夠的彈性能應(yīng)對(duì)變化。
如何實(shí)現(xiàn)分割
切分行為是由客戶端(數(shù)據(jù)的寫入端)發(fā)起的,根據(jù)時(shí)間間隔與數(shù)據(jù)產(chǎn)生時(shí)間將數(shù)據(jù)寫入不同的Index中,為了易于區(qū)分,會(huì)在Index的名字中加上對(duì)應(yīng)的時(shí)間標(biāo)識(shí)
創(chuàng)建新Index這件事,可以是客戶端主動(dòng)發(fā)起一個(gè)創(chuàng)建的請(qǐng)求,帶上具體的Settings、Mappings等信息,但是可能會(huì)有一個(gè)時(shí)間錯(cuò)位,即有新數(shù)據(jù)寫入時(shí)新的Index還沒(méi)有建好,Elasticsearch提供了更優(yōu)雅的方式來(lái)實(shí)現(xiàn)這個(gè)動(dòng)作,即Index Template
分片設(shè)計(jì)
所謂分片設(shè)計(jì),就是如何設(shè)定主分片的個(gè)數(shù)
看上去只是一個(gè)數(shù)字而已,也許在很多場(chǎng)景下,即使不設(shè)定也不會(huì)有問(wèn)題(ES7默認(rèn)是1個(gè)主分片一個(gè)副本分片),但是如果不提前考慮,一旦出問(wèn)題就可能導(dǎo)致系統(tǒng)性能下降、不可訪問(wèn)、甚至無(wú)法恢復(fù),換句話說(shuō),即使使用默認(rèn)值,也應(yīng)該是通過(guò)足夠的評(píng)估后作出的決定,而非拍腦袋定的。
限制分片大小
單個(gè)Shard的存儲(chǔ)大小不超過(guò)30GB
Elastic專家根據(jù)經(jīng)驗(yàn)總結(jié)出來(lái)大家普遍認(rèn)為30GB是個(gè)合適的上限值,實(shí)踐中發(fā)現(xiàn)單個(gè)Shard過(guò)大(超過(guò)30GB)會(huì)導(dǎo)致系統(tǒng)不穩(wěn)定。
其次,為什么不能超過(guò)30GB?主要是考慮Shard Relocate過(guò)程的負(fù)載,我們知道,如果Shard不均衡或者部分節(jié)點(diǎn)故障,Elasticsearch會(huì)做Shard Relocate,在這個(gè)過(guò)程中會(huì)搬移Shard,如果單個(gè)Shard過(guò)大,會(huì)導(dǎo)致CPU、IO負(fù)載過(guò)高進(jìn)而影響系統(tǒng)性能與穩(wěn)定性。
評(píng)估分片數(shù)量
單個(gè)Index的Primary Shard個(gè)數(shù) = k * 數(shù)據(jù)節(jié)點(diǎn)個(gè)數(shù)
在保證第一點(diǎn)的前提下,單個(gè)Index的Primary Shard個(gè)數(shù)不宜過(guò)多,否則相關(guān)的元信息與緩存會(huì)消耗過(guò)多的系統(tǒng)資源,這里的k,為一個(gè)較小的整數(shù)值,建議取值為1,2等,整數(shù)倍的關(guān)系可以讓Shard更好地均勻分布,可以充分的將請(qǐng)求分散到不同節(jié)點(diǎn)上。
小索引設(shè)計(jì)
對(duì)于很小的Index,可以只分配1~2個(gè)Primary Shard的
有些情況下,Index很小,也許只有幾十、幾百M(fèi)B左右,那么就不用按照第二點(diǎn)來(lái)分配了,只分配1~2個(gè)Primary Shard是可以,不用糾結(jié)。
使用索引模板
就是把已經(jīng)創(chuàng)建好的某個(gè)索引的參數(shù)設(shè)置(settings)和索引映射(mapping)保存下來(lái)作為模板,在創(chuàng)建新索引時(shí),指定要使用的模板名,就可以直接重用已經(jīng)定義好的模板中的設(shè)置和映射
Elasticsearch基于與索引名稱匹配的通配符模式將模板應(yīng)用于新索引,也就是說(shuō)通過(guò)索引進(jìn)行匹配,看看新建的索引是否符合索引模板,如果符合,就將索引模板的相關(guān)設(shè)置應(yīng)用到新的索引,如果同時(shí)符合多個(gè)索引模板呢,這里需要對(duì)參數(shù)priority進(jìn)行比較,這樣會(huì)選擇priority大的那個(gè)模板進(jìn)行創(chuàng)建索引。
在創(chuàng)建索引模板時(shí),如果匹配有包含的關(guān)系,或者相同,則必須設(shè)置priority為不同的值,否則會(huì)報(bào)錯(cuò),索引模板也是只有在新創(chuàng)建的時(shí)候起到作用,修改索引模板對(duì)現(xiàn)有的索引沒(méi)有影響,同樣如果在索引中設(shè)置了一些設(shè)置或者mapping都會(huì)覆蓋索引模板中相同的設(shè)置或者mapping
索引模板的用途
索引模板一般用在時(shí)間序列相關(guān)的索引中。
也就是說(shuō), 如果你需要每間隔一定的時(shí)間就建立一次索引,你只需要配置好索引模板,以后就可以直接使用這個(gè)模板中的設(shè)置,不用每次都設(shè)置settings和mappings.
創(chuàng)建索引模板
COPYPUT _index_template/logstash-village
{
"index_patterns": [
"logstash-village-*" // 可以通過(guò)"logstash-village-*"來(lái)適配創(chuàng)建的索引
],
"template": {
"settings": {
"number_of_shards": "3", //指定模板分片數(shù)量
"number_of_replicas": "2" //指定模板副本數(shù)量
},
"aliases": {
"logstash-village": {} //指定模板索引別名
},
"mappings": { //設(shè)置映射
"dynamic": "strict", //禁用動(dòng)態(tài)映射
"properties": {
"@timestamp": {
"type": "date",
"format": "strict_date_optional_time||epoch_millis||yyyy-MM-dd HH:mm:ss"
},
"@version": {
"doc_values": false,
"index": "false",
"type": "integer"
},
"name": {
"type": "keyword"
},
"province": {
"type": "keyword"
},
"city": {
"type": "keyword"
},
"area": {
"type": "keyword"
},
"addr": {
"type": "text",
"analyzer": "ik_smart"
},
"location": {
"type": "geo_point"
},
"property_type": {
"type": "keyword"
},
"property_company": {
"type": "text",
"analyzer": "ik_smart"
},
"property_cost": {
"type": "float"
},
"floorage": {
"type": "float"
},
"houses": {
"type": "integer"
},
"built_year": {
"type": "integer"
},
"parkings": {
"type": "integer"
},
"volume": {
"type": "float"
},
"greening": {
"type": "float"
},
"producer": {
"type": "keyword"
},
"school": {
"type": "keyword"
},
"info": {
"type": "text",
"analyzer": "ik_smart"
}
}
}
}
}
模板參數(shù)
下面是創(chuàng)建索引模板的一些參數(shù)
參數(shù)名稱 參數(shù)介紹
index_patterns 必須配置,用于在創(chuàng)建期間匹配索引名稱的通配符(*)表達(dá)式數(shù)組
template 可選配置,可以選擇包括別名、映射或設(shè)置配置
composed_of 可選配置,組件模板名稱的有序列表。組件模板按指定的順序合并,這意味著最后指定的組件模板具有最高的優(yōu)先級(jí)
priority 可選配置,創(chuàng)建新索引時(shí)確定索引模板優(yōu)先級(jí)的優(yōu)先級(jí)。選擇具有最高優(yōu)先級(jí)的索引模板。如果未指定優(yōu)先級(jí),則將模板視為優(yōu)先級(jí)為0(最低優(yōu)先級(jí))
version 可選配置,用于外部管理索引模板的版本號(hào)
_meta 可選配置,關(guān)于索引模板的可選用戶元數(shù)據(jù),可能有任何內(nèi)容
映射配置
上面我們配置了映射模板,但是我們用到了映射,下面我們說(shuō)下映射
什么是映射
在創(chuàng)建索引時(shí),可以預(yù)先定義字段的類型(映射類型)及相關(guān)屬性
數(shù)據(jù)庫(kù)建表的時(shí)候,我們DDL依據(jù)一般都會(huì)指定每個(gè)字段的存儲(chǔ)類型,例如:varchar、int、datetime等,目的很明確,就是更精確的存儲(chǔ)數(shù)據(jù),防止數(shù)據(jù)類型格式混亂,在Elasticsearch中也是這樣,創(chuàng)建索引的時(shí)候一般也需要指定索引的字段類型,這種方式稱為映射(Mapping)
被動(dòng)創(chuàng)建(動(dòng)態(tài)映射)
此時(shí)字段和映射類型不需要事先定義,只需要存在文檔的索引,當(dāng)向此索引添加數(shù)據(jù)的時(shí)候當(dāng)遇到不存在的映射字段,ES會(huì)根據(jù)數(shù)據(jù)內(nèi)容自動(dòng)添加映射字段定義。
動(dòng)態(tài)映射規(guī)則
使用動(dòng)態(tài)映射的時(shí)候,根據(jù)傳遞請(qǐng)求數(shù)據(jù)的不同會(huì)創(chuàng)建對(duì)應(yīng)的數(shù)據(jù)類型
數(shù)據(jù)類型 Elasticsearch 數(shù)據(jù)類型
null 不添加任何字段
true或者false boolean類型
浮點(diǎn)數(shù)據(jù) float類型
integer數(shù)據(jù) long類型
object object類型
array 取決于數(shù)組中的第一個(gè)非空值的類型。
string 如果此內(nèi)容通過(guò)了日期格式檢測(cè),則會(huì)被認(rèn)為是date數(shù)據(jù)類型 如果此值通過(guò)了數(shù)值類型檢測(cè)則被認(rèn)為是double或者long數(shù)據(jù)類型 帶有關(guān)鍵字子字段會(huì)被認(rèn)為一個(gè)text字段
禁止動(dòng)態(tài)映射
一般生產(chǎn)環(huán)境下需要禁用動(dòng)態(tài)映射,使用動(dòng)態(tài)映射可能出現(xiàn)以下問(wèn)題
造成集群元數(shù)據(jù)一直變更,導(dǎo)致不穩(wěn)定;
可能造成數(shù)據(jù)類型與實(shí)際類型不一致;
如何禁用動(dòng)態(tài)映射,動(dòng)態(tài)mapping的dynamic字段進(jìn)行配置,可選值及含義如下
true:支持動(dòng)態(tài)擴(kuò)展,新增數(shù)據(jù)有新的字段屬性時(shí),自動(dòng)添加對(duì)于的mapping,數(shù)據(jù)寫入成功
false:不支持動(dòng)態(tài)擴(kuò)展,新增數(shù)據(jù)有新的字段屬性時(shí),直接忽略,數(shù)據(jù)寫入成功
strict:不支持動(dòng)態(tài)擴(kuò)展,新增數(shù)據(jù)有新的字段時(shí),報(bào)錯(cuò),數(shù)據(jù)寫入失敗
主動(dòng)創(chuàng)建(顯示映射)
動(dòng)態(tài)映射只能保證最基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu)的映射
所以很多時(shí)候我們需要對(duì)字段除了數(shù)據(jù)結(jié)構(gòu)定義更多的限制的時(shí)候,動(dòng)態(tài)映射創(chuàng)建的內(nèi)容很可能不符合我們的需求,所以可以使用PUT {index}/mapping來(lái)更新指定索引的映射內(nèi)容。
映射類型
我們要?jiǎng)?chuàng)建映射必須還要知道映射類型,否則就會(huì)走默認(rèn)的映射類型,下面我們看看常用的映射類型
準(zhǔn)備工作
我們先創(chuàng)建一個(gè)用于測(cè)試映射類型的索引
COPYPUT mapping_demo
字符串類型
字符串類型是我們最常用的類型之一,我們操作的時(shí)候字符串類型可以被設(shè)置為以下幾種類型
text
當(dāng)一個(gè)字段是要被全文搜索的,比如Email內(nèi)容、產(chǎn)品描述,應(yīng)該使用text類型,text類型會(huì)被分詞
設(shè)置text類型以后,字段內(nèi)容會(huì)被分詞,在生成倒排索引以前,字符串會(huì)被分析器分成一個(gè)一個(gè)詞項(xiàng),text類型的字段不用于排序,很少用于聚合
keyword
keyword類型不會(huì)被分詞,常用于關(guān)鍵字搜索,比如姓名、email地址、主機(jī)名、狀態(tài)碼和標(biāo)簽等
如果字段需要進(jìn)行過(guò)濾(比如查姓名是張三發(fā)布的博客)、排序、聚合,keyword類型的字段只能通過(guò)精確值搜索到,常常被用來(lái)過(guò)濾、排序和聚合
兩者區(qū)別
它們的區(qū)別在于text會(huì)對(duì)字段進(jìn)行分詞處理而keyword則不會(huì)進(jìn)行分詞
也就是說(shuō)如果字段是text類型,存入的數(shù)據(jù)會(huì)先進(jìn)行分詞,然后將分完詞的詞組存入索引,而keyword則不會(huì)進(jìn)行分詞,直接存儲(chǔ),這樣劃分?jǐn)?shù)據(jù)更加節(jié)省內(nèi)存。
使用案例
我們先創(chuàng)建一個(gè)映射,name是keyword類型,描述是text類型的
COPYPUT mapping_demo/_mapping
{
"properties": {
"name": {
"type": "keyword"
},
"city": {
"type": "text",
"analyzer": "ik_smart"
}
}
}
插入數(shù)據(jù)
COPYPUT mapping_demo/_doc/1
{
"name":"北京小區(qū)",
"city":"北京市昌平區(qū)回龍觀街道"
}
對(duì)于keyword的name字段進(jìn)行精確查詢
COPYGET mapping_demo/_search
{
"query": {
"term": {
"name": "北京小區(qū)"
}
}
}
對(duì)于text的city進(jìn)行模糊查詢
COPYGET mapping_demo/_search
{
"query": {
"term": {
"city": "北京市"
}
}
}
數(shù)字類型
數(shù)字類型也是我們最常用的類型之一,下面我們看下數(shù)字類型的使用
類型 取值范圍
long -263 ~ 263
integer -231 ~ 231
short -215 ~ 215
byte -27 ~ 27
double 64位的雙精度 IEEE754 浮點(diǎn)類型
float 32位的雙精度 IEEE754 浮點(diǎn)類型
half_float 16位的雙精度 IEEE754 浮點(diǎn)類型
scaled_float 縮放類型的浮點(diǎn)類型
注意事項(xiàng)
在滿足需求的情況下,優(yōu)先使用范圍小的字段,字段長(zhǎng)度越小,索引和搜索的效率越高。
日期類型
JSON表示日期
JSON沒(méi)有表達(dá)日期的數(shù)據(jù)類型,所以在ES里面日期只能是下面其中之一
格式化的日期字符串,比如:"2015-01-01" or "2015/01/01 12:10:30"
用數(shù)字表示的從新紀(jì)元開(kāi)始的毫秒數(shù)
用數(shù)字表示的從新紀(jì)元開(kāi)始的秒數(shù)(epoch_second)
注意點(diǎn):毫秒數(shù)的值是不能為負(fù)數(shù)的,如果時(shí)間在1970年以前,需要使用格式化的日期表達(dá)
ES如何處理日期
在ES的內(nèi)部,時(shí)間會(huì)被轉(zhuǎn)換為UTC時(shí)間(如果聲明了時(shí)區(qū))并使用從新紀(jì)元開(kāi)始的毫秒數(shù)的長(zhǎng)整形數(shù)字類型的進(jìn)行存儲(chǔ),在日期字段上的查詢,內(nèi)部將會(huì)轉(zhuǎn)換為使用長(zhǎng)整形的毫秒進(jìn)行范圍查詢,根據(jù)與字段關(guān)聯(lián)的日期格式,聚合和存儲(chǔ)字段的結(jié)果將轉(zhuǎn)換回字符串
注意點(diǎn):日期最終都會(huì)作為字符串呈現(xiàn),即使最開(kāi)始初始化的時(shí)候是利用JSON文檔的long聲明的
默認(rèn)日期格式
日期的格式可以被定制化的,如果沒(méi)有聲明日期的格式,它將會(huì)使用默認(rèn)的格式:
COPY"strict_date_optional_time||epoch_millis"
這意味著它將會(huì)接收帶時(shí)間戳的日期,它將遵守strict_date_optional_time限定的格式(yyyy-MM-dd'T'HH:mm:ss.SSSZ 或者 yyyy-MM-dd)或者毫秒數(shù)
日期格式示例
COPYPUT mapping_demo/_mapping
{
"properties": {
"datetime": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
}
}
}
# 添加數(shù)據(jù)
PUT mapping_demo/_doc/2
{
"name":"河北區(qū)",
"city":"河北省小區(qū)",
"datetime":"2022-02-21 11:35:42"
}
日期類型參數(shù)
下面表格里的參數(shù)可以用在date字段上面
參數(shù) 說(shuō)明
doc_values 該字段是否按照列式存儲(chǔ)在磁盤上以便于后續(xù)進(jìn)行排序、聚合和腳本操作,可配置 true(默認(rèn))或 false
format 日期的格式
locale 解析日期中時(shí)使用了本地語(yǔ)言表示月份時(shí)的名稱和/或縮寫,默認(rèn)是 ROOT locale
ignore_malformed 如果設(shè)置為true,則奇怪的數(shù)字就會(huì)被忽略,如果是false(默認(rèn))奇怪的數(shù)字就會(huì)導(dǎo)致異常并且該文檔將會(huì)被拒絕寫入。需要注意的是,如果在腳本參數(shù)中使用則該屬性不能被設(shè)置
index 該字段是否能快速的被查詢,默認(rèn)是true。date類型的字段只有在doc_values設(shè)置為true時(shí)才能被查詢,盡管很慢。
null_value 替代null的值,默認(rèn)是null
on_script_error 定義在腳本中如何處理拋出的異常,fail(默認(rèn))則整個(gè)文檔會(huì)被拒絕索引,continue:繼續(xù)索引
script 如果該字段被設(shè)置,則字段的值將會(huì)使用該腳本產(chǎn)生,而不是直接從source里面讀取。
store true or false(默認(rèn))是否在 _source 之外在獨(dú)立存儲(chǔ)一份
布爾類型
boolean類型用于存儲(chǔ)文檔中的true/false
范圍類型
顧名思義,范圍類型字段中存儲(chǔ)的內(nèi)容就是一段范圍,例如年齡30-55歲,日期在2020-12-28到2021-01-01之間等
類型范圍
es中有六種范圍類型:
integer_range
float_range
long_range
double_range
date_range
ip_range
使用實(shí)例
COPYPUT mapping_demo/_mapping
{
"properties": {
"age_range": {
"type": "integer_range"
}
}
}
# 指定年齡范圍,可以使用 gt、gte、lt、lte。
PUT mapping_demo/_doc/3
{
"name":"張三",
"age_range":{
"gt":20,
"lt":30
}
}
分詞器
什么是分詞器
分詞器的主要作用將用戶輸入的一段文本,按照一定邏輯,分析成多個(gè)詞語(yǔ)的一種工具
顧名思義,文本分析就是把全文本轉(zhuǎn)換成一系列單詞(term/token)的過(guò)程,也叫分詞,在 ES 中,Analysis 是通過(guò)分詞器(Analyzer) 來(lái)實(shí)現(xiàn)的,可使用 ES 內(nèi)置的分析器或者按需定制化分析器。
舉一個(gè)分詞簡(jiǎn)單的例子:比如你輸入 Mastering Elasticsearch,會(huì)自動(dòng)幫你分成兩個(gè)單詞,一個(gè)是 mastering,另一個(gè)是 elasticsearch,可以看出單詞也被轉(zhuǎn)化成了小寫的。
分詞器構(gòu)成
分詞器是專門處理分詞的組件,分詞器由以下三部分組成:
character filter
接收原字符流,通過(guò)添加、刪除或者替換操作改變?cè)址?br>
例如:去除文本中的html標(biāo)簽,或者將羅馬數(shù)字轉(zhuǎn)換成阿拉伯?dāng)?shù)字等,一個(gè)字符過(guò)濾器可以有零個(gè)或者多個(gè)
tokenizer
簡(jiǎn)單的說(shuō)就是將一整段文本拆分成一個(gè)個(gè)的詞
例如拆分英文,通過(guò)空格能將句子拆分成一個(gè)個(gè)的詞,但是對(duì)于中文來(lái)說(shuō),無(wú)法使用這種方式來(lái)實(shí)現(xiàn),在一個(gè)分詞器中,有且只有一個(gè)tokenizeer
token filters
將切分的單詞添加、刪除或者改變
例如將所有英文單詞小寫,或者將英文中的停詞a刪除等,在token filters中,不允許將token(分出的詞)的position或者offset改變,同時(shí),在一個(gè)分詞器中,可以有零個(gè)或者多個(gè)token filters。
分詞順序
同時(shí) Analyzer 三個(gè)部分也是有順序的,從圖中可以看出,從上到下依次經(jīng)過(guò) Character Filters,Tokenizer 以及 Token Filters,這個(gè)順序比較好理解,一個(gè)文本進(jìn)來(lái)肯定要先對(duì)文本數(shù)據(jù)進(jìn)行處理,再去分詞,最后對(duì)分詞的結(jié)果進(jìn)行過(guò)濾。
測(cè)試分詞
可以通過(guò)_analyzerAPI來(lái)測(cè)試分詞的效果,我們使用下面的html過(guò)濾分詞
COPYPOST _analyze
{
"text":"<b>hello world<b>" # 輸入的文本
"char_filter":["html_strip"], # 過(guò)濾html標(biāo)簽
"tokenizer":"keyword", #原樣輸出
}
什么時(shí)候分詞
文本分詞會(huì)發(fā)生在兩個(gè)地方:
創(chuàng)建索引:當(dāng)索引文檔字符類型為text時(shí),在建立索引時(shí)將會(huì)對(duì)該字段進(jìn)行分詞。
搜索:當(dāng)對(duì)一個(gè)text類型的字段進(jìn)行全文檢索時(shí),會(huì)對(duì)用戶輸入的文本進(jìn)行分詞。
創(chuàng)建索引時(shí)指定分詞器
如果設(shè)置手動(dòng)設(shè)置了分詞器,ES將按照下面順序來(lái)確定使用哪個(gè)分詞器
先判斷字段是否有設(shè)置分詞器,如果有,則使用字段屬性上的分詞器設(shè)置
如果設(shè)置了analysis.analyzer.default,則使用該設(shè)置的分詞器
如果上面兩個(gè)都未設(shè)置,則使用默認(rèn)的standard分詞器
字段指定分詞器
為addr屬性指定分詞器,這里我們使用的是中文分詞器
COPYPUT my_index
{
"mappings": {
"properties": {
"info": {
"type": "text",
"analyzer": "ik_smart"
}
}
}
}
設(shè)置默認(rèn)分詞器
COPYPUT my_index
{
"settings": {
"analysis": {
"analyzer": {
"default":{
"type":"simple"
}
}
}
}
}
搜索時(shí)指定分詞器
在搜索時(shí),通過(guò)下面參數(shù)依次檢查搜索時(shí)使用的分詞器,這樣我們的搜索語(yǔ)句就會(huì)先分詞,然后再來(lái)進(jìn)行搜索
搜索時(shí)指定analyzer參數(shù)
創(chuàng)建mapping時(shí)指定字段的search_analyzer屬性
創(chuàng)建索引時(shí)指定setting的analysis.analyzer.default_search
查看創(chuàng)建索引時(shí)字段指定的analyzer屬性
如果上面幾種都未設(shè)置,則使用默認(rèn)的standard分詞器。
指定analyzer
搜索時(shí)指定analyzer查詢參數(shù)
COPYGET my_index/_search
{
"query": {
"match": {
"message": {
"query": "Quick foxes",
"analyzer": "stop"
}
}
}
}
指定字段analyzer
COPYPUT my_index
{
"mappings": {
"properties": {
"title":{
"type":"text",
"analyzer": "whitespace",
"search_analyzer": "simple"
}
}
}
}
指定默認(rèn)default_seach
COPYPUT my_index
{
"settings": {
"analysis": {
"analyzer": {
"default":{
"type":"simple"
},
"default_seach":{
"type":"whitespace"
}
}
}
}
}
內(nèi)置分詞器
es在索引文檔時(shí),會(huì)通過(guò)各種類型 Analyzer 對(duì)text類型字段做分析
不同的 Analyzer 會(huì)有不同的分詞結(jié)果,內(nèi)置的分詞器有以下幾種,基本上內(nèi)置的 Analyzer 包括 Language Analyzers 在內(nèi),對(duì)中文的分詞都不夠友好,中文分詞需要安裝其它 Analyzer
分析器 描述 分詞對(duì)象 結(jié)果
standard 標(biāo)準(zhǔn)分析器是默認(rèn)的分析器,如果沒(méi)有指定,則使用該分析器。它提供了基于文法的標(biāo)記化(基于 Unicode 文本分割算法,如 Unicode 標(biāo)準(zhǔn)附件 # 29所規(guī)定) ,并且對(duì)大多數(shù)語(yǔ)言都有效。The 2 QUICK Brown-Foxes jumped over the lazy dog’s bone. [ the, 2, quick, brown, foxes, jumped, over, the, lazy, dog’s, bone ]
simple 簡(jiǎn)單分析器將文本分解為任何非字母字符的標(biāo)記,如數(shù)字、空格、連字符和撇號(hào)、放棄非字母字符,并將大寫字母更改為小寫字母。The 2 QUICK Brown-Foxes jumped over the lazy dog’s bone. [ the, quick, brown, foxes, jumped, over, the, lazy, dog, s, bone ]
whitespace 空格分析器在遇到空白字符時(shí)將文本分解為術(shù)語(yǔ) The 2 QUICK Brown-Foxes jumped over the lazy dog’s bone. [ The, 2, QUICK, Brown-Foxes, jumped, over, the, lazy, dog’s, bone. ]
stop 停止分析器與簡(jiǎn)單分析器相同,但增加了刪除停止字的支持。默認(rèn)使用的是 _english_ 停止詞。The 2 QUICK Brown-Foxes jumped over the lazy dog’s bone. [ quick, brown, foxes, jumped, over, lazy, dog, s, bone ]
keyword 不分詞,把整個(gè)字段當(dāng)做一個(gè)整體返回 The 2 QUICK Brown-Foxes jumped over the lazy dog’s bone. [The 2 QUICK Brown-Foxes jumped over the lazy dog’s bone.]
pattern 模式分析器使用正則表達(dá)式將文本拆分為術(shù)語(yǔ)。正則表達(dá)式應(yīng)該匹配令牌分隔符,而不是令牌本身。正則表達(dá)式默認(rèn)為 w+ (或所有非單詞字符)。The 2 QUICK Brown-Foxes jumped over the lazy dog’s bone. [ the, 2, quick, brown, foxes, jumped, over, the, lazy, dog, s, bone ]
多種西語(yǔ)系 arabic, armenian, basque, bengali, brazilian, bulgarian, catalan, cjk, czech, danish, dutch, english等等 一組旨在分析特定語(yǔ)言文本的分析程序。
IK中文分詞器
IKAnalyzer
IKAnalyzer是一個(gè)開(kāi)源的,基于java的語(yǔ)言開(kāi)發(fā)的輕量級(jí)的中文分詞工具包
從2006年12月推出1.0版開(kāi)始,IKAnalyzer已經(jīng)推出了3個(gè)大版本,在 2012 版本中,IK 實(shí)現(xiàn)了簡(jiǎn)單的分詞歧義排除算法,標(biāo)志著 IK 分詞器從單純的詞典分詞向模擬語(yǔ)義分詞衍化
中文分詞器算法
中文分詞器最簡(jiǎn)單的是ik分詞器,還有jieba分詞,哈工大分詞器等
分詞器 描述 分詞對(duì)象 結(jié)果
ik_smart ik分詞器中的簡(jiǎn)單分詞器,支持自定義字典,遠(yuǎn)程字典 學(xué)如逆水行舟,不進(jìn)則退 [學(xué)如逆水行舟,不進(jìn)則退]
ik_max_word ik_分詞器的全量分詞器,支持自定義字典,遠(yuǎn)程字典 學(xué)如逆水行舟,不進(jìn)則退 [學(xué)如逆水行舟,學(xué)如逆水,逆水行舟,逆水,行舟,不進(jìn)則退,不進(jìn),則,退]
ik_smart
原始內(nèi)容
COPY傳智教育的教學(xué)質(zhì)量是杠杠的
測(cè)試分詞
COPYGET _analyze
{
"analyzer": "ik_smart",
"text": "傳智教育的教學(xué)質(zhì)量是杠杠的"
}
ik_max_word
原始內(nèi)容
COPY傳智教育的教學(xué)質(zhì)量是杠杠的
測(cè)試分詞
COPYGET _analyze
{
"analyzer": "ik_max_word",
"text": "傳智教育的教學(xué)質(zhì)量是杠杠的"
}
作者:陳燁123
歡迎關(guān)注微信公眾號(hào) :java知路