大家好,我是咔咔 不期速成,日拱一卒
專案中準備使用ElasticSearch,之前只是對ElasticSearch有過簡單的瞭解沒有系統的學習,本系列文章將從基礎的學習再到深入的使用。
咔咔之前寫了一份死磕MySQL文章,如今再入一個系列玩轉ElasticSearch。
本期文章會帶給大家學習ElasticSearch的基礎入門,先把基礎學會再深入學習更多的知識點。
一、基本概念
文件(Document)
ElasticSearch是面向文件的,文件是所有可搜尋資料的最小單位,例如MySQL的一條資料記錄
文件會被序列化成為json格式,儲存在ElasticSearch中
每個文件都有一個唯一ID,例如MySQL中的主鍵ID
JSON文件
一篇文件包括了一系列的欄位,例如資料中的一條記錄
json文件,格式靈活,不需要預先定義格式
在上期文章中把csv檔案格式檔案通過Logstash轉化為json儲存到ElasticSearch中
文件的後設資料
index :文件所屬的索引名
type:文件所屬型別名
id:文件唯一ID
source:文件的原始JSON資料
version:文件的版本資訊
score:相關性分數
索引
索引是文件的容器,是一類文件的結合,每個索引都有自己的mapping定義,用於定義包含的文件的欄位和型別
每個索引都可以定義mapping,setting,mapping是定義欄位型別,setting定義不同的資料分佈
{
"movies" : {
"aliases" : { },
"mappings" : {
"properties" : {
"@version" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"genre" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"id" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"title" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"year" : {
"type" : "long"
}
}
},
"settings" : {
"index" : {
"creation_date" : "1641637408626",
"number_of_shards" : "1",
"number_of_replicas" : "1",
"uuid" : "gf0M2BgnStGZZHsIJD6otQ",
"version" : {
"created" : "7010099"
},
"provided_name" : "movies"
}
}
}
}
Type
7.0之前,一個Index可以設定多個type,所以當時大多數資料顯示的都是type型別與資料庫的表
7.0之後,一個索引只能建立一個type“_doc”
若不好理解,可以對比MySQL類比一下
Databases | ElasticSearch |
---|---|
Table | Index(Type) |
Row | Document |
Column | Filed |
Schema | Mapping |
Sql | Dsl |
節點
節點是一個ElasticSearch的例項,本質上就是java的一個程式,一臺機器可以執行多個ElasticSearch程式,但生產環境下還是建議一臺伺服器執行一個ElasticSearch例項
每個節點都有名字,通過配置檔案配置,或者啟動時 -E node.name=node1
每個節點在啟動後,會分配一個UID,儲存在data目錄下
主節點:master
預設情況下任何一個叢集中的節點都有可能被選為主節點,職責是建立索引、刪除索引、跟蹤叢集中的節點、決定分片分配給相應的節點。索引資料和搜尋查詢操作會佔用大量的記憶體、cpu、io資源。因此,為了保證一個叢集的穩定性,應該主動分離主節點跟資料節點。
資料節點:data
看名字就知道是儲存索引資料的節點,主要用來增刪改查、聚合操作等。資料節點對記憶體、cpu、io要求比較高,在優化的時候需要注意監控資料節點的狀態,當資源不夠的時候,需要在叢集中新增新的節點。
負載均衡節點:client
該節點只能處理路由請求,處理搜尋,分發索引等操作,該節點類似於Nginx的負載均衡處理,獨立的客戶端節點在一個比較大的叢集中是非常有用的,它會協調主節點、資料節點、客戶端節點加入叢集的狀態,根據叢集的狀態可以直接路由請求。
預處理節點:ingest
在索引資料之前可以先對資料做預處理操作,所有節點其實預設都是支援ingest操作的,也可以專門將某個節點配置為ingest節點。
分片
分片分為主分片,副本分片
主分片:用以解決資料水平擴充套件的問題,將資料分佈到叢集內的所有節點上,一個分片是一個執行的Lucene(搜尋引擎)例項,主分片數在建立時指定,後續不允許修改,除非Reindex
副本:用以解決資料高可用的問題,可以理解為主分片的拷貝,增加副本數,還可以在一定程度上提高服務的可用性。
在生產環境中分片的設定有何影響
分片數設定過小會導致無法增加節點實現水平擴充套件,單個分片資料量太大,導致資料重新分配耗時。假設你給索引設定了三個主分片 ,這時你給叢集加了幾個例項,索引也只能在三臺伺服器上
分片數設定過大導致搜尋結果相關性打分,影響統計結果的準確性,單個節點上過多的分片,會導致資源浪費,同時也會影響效能
從ElasticSearch7.0開始,預設的主分片設定為1,解決了over-sharding的問題
檢視叢集健康狀態
執行介面
get _cluster/health
green:主分片與副本都正常分配
yellow:主分片全部正常分配,有副本分片未能正常分配
red:有主分片未能分配,當伺服器的磁碟容量超過85%時建立了一個索引
二、Result Api
介面 | 作用 |
---|---|
get movies | 檢視索引相關資訊 |
get movies/_count | 檢視索引的文件總數 |
post movies/_search | 檢視前10條文件 |
get /_cat/indices/movies?v&s=index | 獲取索引狀態 |
get /_cat/indices?v&health=green | 檢視狀態為綠色的索引 |
get /_cat/indices?v&s=docs.count:desc | 根據文件資料倒序 |
get /_cat/indices/kibana*?pri&v&h=health,index,pri,rep,docs,count,mt | 檢視索引具體欄位 |
get /_cat/indices?v&h=i,tm&s=tm:desc | 檢視索引所佔的記憶體 |
get _cluster/health | 檢視叢集健康狀態 |
三、文件的基本CRUD操作
create 一個文件
支援自動生成文件ID和指定文件ID兩種方式
通過呼叫post /movies/_doc 系統會自動生成文件ID
使用http put movies/_create/1 建立時,url中顯示指定_create ,如果該id的文件已經存在,操作失敗
Index 文件
Index和Create區別在於,如果文件不存在,就索引新的文件。否則現有文件會被刪除,新的文件被索引並且版本資訊+1
可以看到之前的文件已經被更新為最新的niuniu,是因為之前就存在文件id=1,並且能看到版本資訊也加了1
update 文件
update方法不會刪除原有文件,而是實現真正的資料更新
get 一個文件
檢索文件找到,返回狀態碼200,文件元資訊,這裡需要注意一下版本資訊,同一個id的文件,即被刪除版本號也會不斷增加
找不到文件,返回狀態碼404
Bulk Api
支援在一次Api呼叫中,對不同的索引進行操作,支援index、create、update、delete
可以在url中指定index,也可以在請求的payload中進行
操作中單條操作失敗,不會影響其它繼續操作,並且返回結果包括了每一條操作執行的結果
多索引bulk批量操作案例:
post _bulk
{"index":{"_index" : "test1","_id" : "1"}}
{"name":"kaka_bulk"}
{"delete":{"_index":"test1","_id":"2"}}
{"create":{"_index":"test2","_id":"3"}}
{"name":"kaka_create"}
{"update":{"_id":"1","_index":"test1"}}
{"doc":{"name":"kaka_bulk"}}
返回結果
{
"took" : 165,
"errors" : false,
"items" : [
{
"index" : {
"_index" : "test1",
"_type" : "_doc",
"_id" : "1",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1,
"status" : 201
}
},
{
"delete" : {
"_index" : "test1",
"_type" : "_doc",
"_id" : "2",
"_version" : 1,
"result" : "not_found",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 1,
"_primary_term" : 1,
"status" : 404
}
},
{
"create" : {
"_index" : "test2",
"_type" : "_doc",
"_id" : "3",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1,
"status" : 201
}
},
{
"update" : {
"_index" : "test1",
"_type" : "_doc",
"_id" : "1",
"_version" : 1,
"result" : "noop",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"status" : 200
}
}
]
}
這裡需要大家注意:bulk api 對json語法有嚴格的要求,每個json串不能換行,只能放一行,同時一個json和另一個json串之間必須有一個換行。
單索引bulk批量操作
如果操作的是同一個索引時,bulk語句還可以變化為以下方式
post test1/_bulk
{"index":{"_id" : "1"}}
{"name":"kaka_bulk"}
{"delete":{"_id":"2"}}
{"create":{"_id":"3"}}
{"name":"kaka_create"}
{"update":{"_id":"1"}}
{"doc":{"name":"kaka_bulk"}}
單條的返回結果可以自己嘗試一下,可以看到單索引bulk跟多索引bulk之間的區別顯而易見。
bulk size的最佳大小
bulk request 會載入到記憶體裡,如果太大的話,效能反而會下降,因此需要不斷嘗試最佳的bulk size,大小最好控制在5~15MB即可,至於條數需要根據當下資料量再調整。
批量讀取_mget
道理跟MySQL都一樣,只要是批量在一定合理的範圍內都會減少網路連線所產生的開銷,從而提高效能
需要注意批量獲取每個json之間是需要逗號隔開的,否則會報json解析異常
get /_mget
{
"docs": [
{"_index":"test","_id":"1"},
{"_index":"movies","_id":"2"}
]
}
批量搜尋_msearch
post kibana_sample_data_ecommerce/_msearch
{}
{"query":{"match_all":{}},"size":1}
{"index":"kibana_smaple_sample_data_flights"}
{"query":{"match_all":{}},"size":1}
常見的錯誤狀態
問題 | 原因 |
---|---|
無法連線 | 網路故障、叢集異常 |
連線無法關閉 | 網路故障、節點出錯 |
429 | 叢集過於繁忙 |
4xx | 請求體格式錯誤 |
500 | 叢集內部錯誤 |
四、倒排索引
倒排索引是由單詞詞典、倒排列表兩部分組成,單詞詞典記錄的所有文件的單詞,記錄單詞倒排列表的關聯關係
倒排列表記錄了單詞對應的文件結合,由倒排索引項組成,分別為文件ID、詞頻TF、位置、偏移
案例:
文件ID | 文件內容 |
---|---|
1 | kaka ElasticSearch |
2 | ElasticSearch kaka |
3 | ElasticSearch niuniu |
倒排列表就為:
文件ID | 詞頻 | 位置 | 偏移量 |
---|---|---|---|
1 | 1 | 1 | <10,23> |
2 | 1 | 0 | <0,13> |
3 | 1 | 0 | <0,13> |
ElasticSearch可以為json文件中的每個欄位設定自己的倒排索引,也可以指定某些欄位不做倒排索引
若不做倒排索引,雖可以節省儲存空間,但欄位無法被搜尋
五、使用Analyzer進行分詞
首先你得知道什麼是分詞:Analysis把全文字轉換為一系列單詞的過程叫做分詞
Analysis通過Analyzer實現的,可以通過ElasticSearch內建的分析器、或使用定製分析器
分詞器除了寫入時轉換此條,查詢query時也需要用相同的分析器對查詢語句進行分析
案例:ElasticSearch kaka
通過分詞就轉化為 elasticSearch和kaka,這裡需要注意的是通過分詞轉化後把單詞的首字母變為小寫
Analyzer的組成
Character Fiters :針對原始文字處理,例如去除html
Tokenizer : 按照規則切分單詞
Token Filter : 將切分的單詞進行加工,轉為小寫,刪除stopwords並增加同義詞
ElasticSearch的內建分詞器
# Standard Analyzer - 預設分詞器,按詞切分,小寫處理
# 只做單詞分割、並且把單詞轉為小寫
get _analyze
{
"analyzer":"standard",
"text":"If you don't expect quick success, you'll get a pawn every day"
}
# Simple Analyzer - 按照非字母切分(符號被過濾),小寫處理
# 按照非字母切分例如字母與字母之間的——,非字母的都被去除例如下邊的 2
get _analyze
{
"analyzer" :"simple",
"text":"3 If you don't expect quick success, you'll get a pawn every day kaka-niuniu"
}
# Whitespace Analyzer - 按照空格切分,不轉小寫
# 僅僅是根據空格切分,再無其它
get _analyze
{
"analyzer":"whitespace",
"text":"3 If you don't expect quick success, you'll get a pawn every day"
}
# Stop Analyzer - 小寫處理,停用詞過濾(the,a, is)
# 按照非字母切分例如字母與字母之間的——,非字母的都被去除例如下邊的 2
# 相比Simple Analyze,會把the,a,is等修飾性詞語去除
get _analyze
{
"analyzer":"stop",
"text":"4 If you don't expect quick success, you'll get a pawn every day"
}
# Keyword Analyzer - 不分詞,直接將輸入當作輸出
# 不做任何分詞,直接把輸入的輸出,假如你不想使用任何分詞時就可以使用這個
get _analyze
{
"analyzer":"keyword",
"text":"5 If you don't expect quick success, you'll get a pawn every day"
}
# Patter Analyzer - 正規表示式,預設\W+(非字元分隔)
# 通過正規表示式進行分詞,預設是\W+,非字元的符號進行分割
get _analyze
{
"analyzer":"pattern",
"text":"6 If you don't expect quick success, you'll get a pawn every day"
}
# Language 一提供了30多種常見語言的分詞器
# 通過不同語言進行分詞
# 會把複數轉為單數 ,會把單詞的ing去除
get _analyze
{
"analyzer":"english",
"text":"7 If you don't expect quick success, you'll get a pawn every day kakaing kakas"
}
# 中文分詞器
# 這個需要安裝
# 執行: ./bin/elasticsearch-plugin install analysis-icu
# 重啟:nohup ./bin/elasticsearch > /dev/null 2>&1 &
get _analyze
{
"analyzer":"icu_analyzer",
"text":"你好,我是咔咔"
}
其它中文分詞
用的最多的IK分詞,只是自定義詞庫,支援熱更新分詞字典
清華大學自然語言一套分詞器Thulac
六、Search Api
通過Url query 實現搜尋
例如:
get /movies/_search?q=2012&df=title&sort=year:desc
q:指定查詢語句,使用Query String Syntax
df:查詢欄位,不指定時,會對所有欄位進行查詢
sort:排序、from和size用於分頁
Profile:可以檢視查詢是如果被執行的
指定欄位查詢、泛查詢
指定欄位查詢就是加上df即可、泛查詢什麼都不加,看案例
通過下圖右側資訊可得知,指定欄位查詢的是title中存在2012的資料
同樣也可以這樣來寫指定欄位查詢
get /movies/_search?q=2012&df=title
{
"profile":true
}
通過下圖右側可得知,泛查詢則是在所有欄位中查詢存在2012的數
分組與引號查詢
若你查詢值為Beautiful Mind 則等效於Beautiful OR Mind ,類似於MySQL中的or語句,意思為查詢的欄位中包含 Beautiful 或者 Mind 都會被查詢出來
若你查詢值為"Beautiful Mind" 則等效於Beautiful AND Mind ,類似於MySQL中的and語句,意思為查詢的欄位中不僅要包含Beautiful 而且還需要包含 Mind ,跟MySQL中不同的是順序也不能變
注意:這裡你乍一眼看過去沒啥區別, 其實區別就在於有無引號
# PhraseQuery
# 需要欄位title中存在beautiful 和 mind,並且兩者的順序不能亂
# "description" : """title:"beautiful mind""""
get /movies/_search?q=title:"Beautiful Mind"
{
"profile":"true"
}
# TermQuery
# 需要欄位title中出現beautiful 或 mind 都可以
# "type" : "BooleanQuery",
# "description" : "title:beautiful title:mind",
get /movies/_search?q=title:(Beautiful Mind)
{
"profile":"true"
}
布林操作
可以使用AND / OR / NOT 或者 && / || / ! 這裡你會發現使用的都是大寫,+表示must(必須存在),-表示not mast(必須不存在)接下來看案例
# title 裡邊必須有beautiful 和 mind
# "description" : "+title:beautiful +title:mind"
get /movies/_search?q=title:(Beautiful AND Mind)
{
"profile":"true"
}
# title裡邊包含beautiful 必須沒有mind
# "description" : "title:beautiful -title:mind"
get /movies/_search?q=title:(Beautiful NOT Mind)
{
"profile":"true"
}
# title裡包含beautiful ,必須也包含mind
# "description" : "title:beautiful +title:mind"
get /movies/_search?q=title:(Beautiful %2BMind)
{
"profile":"true"
}
範圍查詢、萬用字元查詢、模糊匹配
# year年份大於1996的電影
# 注意一下[] 為閉區間 {}為開區間
# "description" : "year:[1997 TO 9223372036854775807]"
get /movies/_search?q=year:>1996
{
"profile":"true"
}
# title 中存在b的資料
# "description" : "title:b*"
get /movies/_search?q=title:b*
{
"profile":"true"
}
# 對於模糊匹配還是非常有必要的,因為會存在一起使用者會輸錯單詞,我們就可以給做近似度匹配
# "description" : "(title:beautiful)^0.875"
get /movies/_search?q=title:beautifl~1
{
"profile":"true"
}
七、Request Body Search
在日常開發過程中,最經常用的還是在Request Body中做,接下來跟著咔咔的例項一點點走
正常查詢
sort :需要排序的欄位
source:查那些欄位
from:頁數
size:每頁數量
post movies/_search
{
"profile":"true",
"sort":[{"year":"desc"}],
"_source":["year"],
"from":0,
"size":2,
"query":{
"match_all": {}
}
}
指令碼欄位
這個應用場景跟咔咔近期做的外幣功能是非吻合,每筆合同都有自己不同的匯率,要算出這筆合同金額是多少
post /movies/_search
{
"script_fields":{
"new_field":{
"script":{
"lang":"painless",
"source":"doc['year'].value+'年'"
}
}
},
"query":{
"match_all": {}
}
}
這個案例就是把當前資料的year 拼上 “年” 組成的新欄位然後返回,返回結果如下
{
"_index" : "movies",
"_type" : "_doc",
"_id" : "3844",
"_score" : 1.0,
"fields" : {
"new_field" : [
"1989年"
]
}
}
從上面的結果可以看到只返回了指令碼欄位,沒有返回原始欄位,那如何讓原始欄位也跟著一起返回呢?
只需要在request body中加上_source
即可,當然也可以查詢指定欄位"_source":["id","title"]
post /movies/_search
{
"_source":"*",
"script_fields":{
"new_field":{
"script":{
"lang":"painless",
"source":"doc['year'].value+'年'"
}
}
},
"query":{
"match_all": {}
}
}
檢視返回結果
{
"_index" : "movies",
"_type" : "_doc",
"_id" : "3843",
"_score" : 1.0,
"_source" : {
"year" : 1983,
"@version" : "1",
"genre" : [
"Horror"
],
"id" : "3843",
"title" : "Sleepaway Camp"
},
"fields" : {
"new_field" : [
"1983年"
]
}
}
查詢表示式Match
# title中包含sleepaway 或者 camp 即可
# 可以看到跟 url 的get /movies/_search?q=title:(Beautiful Mind) 分組查詢返回結果是一致的
# "description" : "title:sleepaway title:camp"
get /movies/_doc/_search
{
"query":{
"match":{
"title":"Sleepaway Camp"
}
},
"profile":"true"
}
# title中必須包含sleepaway 和 camp 並且順序不能亂
# 可以看到跟 url 的get /movies/_search?q=title:(Beautiful AND Mind)是一致的
# "description" : "+title:sleepaway +title:camp"
get /movies/_doc/_search
{
"query":{
"match":{
"title":{
"query":"Sleepaway Camp",
"operator":"AND"
}
}
},
"profile":"true"
}
# title 中查詢Sleepaway 和 Camp中間可以有一個任意值插入
# get /movies/_search?q=title:beautifl~1
# "description" : """title:"sleepaway camp"~1"""
get /movies/_doc/_search
{
"query":{
"match_phrase":{
"title":{
"query":"Sleepaway Camp",
"slop":1
}
}
},
"profile":"true"
}
八、 Query String 和 Simple Query String
# Query String 中可以使用and跟url 的query string一樣
# title 中必須存在sleepaway 和 camp 即可
# 跟url的 get /movies/_search?q=title:(Beautiful Mind) 一致
# "description" : "+title:sleepaway +title:camp"
post /movies/_search
{
"query":{
"query_string":{
"default_field":"title",
"query":"Sleepaway AND Camp"
}
},
"profile":"true"
}
# simple_query_string 不支援and的使用,可以看到是把and當做一個詞來進行查詢
# title 中存在sleepaway 或 camp 即可
# "description" : "title:sleepaway title:and title:camp"
post /movies/_search
{
"query":{
"simple_query_string": {
"query": "Sleepaway AND Camp",
"fields": ["title"]
}
},
"profile":"true"
}
# 如果想讓simple_query_string 執行布林操作,則需要給加上default_operator
# title中必須存在sleepaway 和 camp 即可
# "description" : "+title:sleepaway +title:camp"
post /movies/_search
{
"query":{
"simple_query_string": {
"query": "Sleepaway Camp",
"fields": ["title"],
"default_operator": "AND"
}
},
"profile":"true"
}
九、Mapping和常見欄位型別
什麼是Mapping
Mapping類似於資料庫中的schema,主要包括定義索引的欄位名稱,定義欄位的資料型別,配置倒排索引設定
什麼是Dynamic Mapping
Mapping有一個屬性為dynamic,其定義瞭如何處理新增文件中包含的新增欄位,其有三個值可選預設為true
true:一旦有新增欄位的文件寫入,Mapping也同時被更新
false:Mapping不會被更新並且新增的欄位也不會被索引,但是資訊會出現在_source中
strict:文件寫入失敗
常見型別
Json型別 | ElasticSearch型別 |
---|---|
字串 | 日期格式為data、浮點數為float、整數為long、設定為text並且增加keyword子欄位 |
布林值 | boolean |
浮點數 | float |
整數 | long |
物件 | object |
陣列 | 取第一個非空數值的型別所定 |
控制 | 忽略 |
put kaka/_doc/1
{
"text":"kaka",
"int":10,
"boole_text":"false",
"boole":true,
"float_text":"1.234",
"float":1.234,
"loginData":"2005-11-24T22:20"
}
# 獲取索引kaka的mapping
get kaka/_mapping
返回結果,從結果中可得知如果是false或者true在引號裡邊就是text型別需要注意這一點就行
{
"kaka" : {
"mappings" : {
"properties" : {
"boole" : {
"type" : "boolean"
},
"boole_text" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"float" : {
"type" : "float"
},
"float_text" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"int" : {
"type" : "long"
},
"loginData" : {
"type" : "date"
},
"text" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}
}
}
自定義Mapping
設定欄位不被索引
設定欄位不被索引使用index,只需要給欄位在加一個index:false即可,同時注意一下mapping的設定格式
按照咔咔給的步驟走,你會得到一個這樣的錯誤Cannot search on field [mobile] since it is not indexed
,意思就是不能搜尋沒有索引的欄位
put kaka
{
"mappings":{
"properties":{
"firstName":{
"type":"text"
},
"lastName":{
"type":"text"
},
"mobile":{
"type":"text",
"index":false
}
}
}
}
post /kaka/_doc/1
{
"firstName":"kaka",
"lastName":"Niu",
"mobile":"123456"
}
get /kaka/_search
{
"query":{
"match": {
"mobile":"123456"
}
}
}
設定copy_to
設定方式如下,copy_to設定後再搜尋時可以直接使用你定義的欄位進行搜尋
put kaka
{
"mappings":{
"properties":{
"firstName":{
"type":"text",
"copy_to":"allSearch"
},
"lastName":{
"type":"text",
"copy_to":"allSearch"
}
}
}
}
為了方便檢視,這裡咔咔再插入兩條資料
post /kaka/_doc/1
{
"fitstName":"kaka",
"lastName":"niuniu"
}
post /kaka/_doc/2
{
"fitstName":"kaka",
"lastName":"kaka niuniu"
}
進行查詢,返回的只有id為2的這條資料,所以說使用copy_to後,代表著所有欄位中都包含搜尋的詞
post /kaka/_search
{
"query":{
"match":{
"allSearch":"kaka"
}
},
"profile":"true"
}
十、自定義分詞器
分詞器是由Character Fiters、Tokenizer、Token Filter組成的
Character Filters 主要是對文字的替換、增加、刪除,可以配置多個Character Filters ,需要注意的是設定後會影響Tokenizer的position、offset資訊
Character Filters 自帶的有 HTMl strip 去除html標籤、Mapping 字串的替換、Pattern replace 正則匹配替換
Tokenizer 處理的就是分詞,內建了非常多的分詞詳細可以在第二期文章中檢視
Token Filters 是將Tokenizer 分詞後的單詞進行增加、修改、刪除,例如進行轉為lowercase小寫字母、stop去除修飾詞、synonym近義詞等
自定義Character Filters
# Character Fiters之html的替換
# 會把text中的html標籤都會去除掉
post /_analyze
{
"tokenizer":"keyword",
"char_filter":["html_strip"],
"text":"<span>咔咔閒談</span>"
}
# Character Fiters之替換值
# 會把text中的 i 替換為 kaka、hope 替換為 wish
post /_analyze
{
"tokenizer":"keyword",
"char_filter":[
{
"type":"mapping",
"mappings":["i => kaka","hope => wish"]
}
],
"text":"I hope,if you don't expect quick success, you'll get a pawn every day."
}
# Character Fiters之正規表示式
# 使用正規表示式來獲取域名資訊
post /_analyze
{
"tokenizer":"keyword",
"char_filter":[
{
"type":"pattern_replace",
"pattern":"http://(.*)",
"replacement":"$1"
}
],
"text":"http://www.kakaxiantan.com"
}
自定義Token Filters
現在用的分詞器是whitespace
,這個分詞器是把詞使用空格 隔開,但是現在還想讓詞變小寫並過濾修飾詞,應該怎麼做呢?
post /_analyze
{
"tokenizer":"whitespace",
"filter":["stop","lowercase"],
"text":"If on you don't expect quick success, you'll get a pawn every day"
}
為了不佔地方,只複製出了代表性的返回結果
{
"tokens" : [
{
"token" : "if",
"start_offset" : 0,
"end_offset" : 2,
"type" : "word",
"position" : 0
},
{
"token" : "you",
"start_offset" : 6,
"end_offset" : 9,
"type" : "word",
"position" : 2
}
]
}
實戰自定義分詞
本節開篇就知道analyze是通過Character Fiters、Tokenizer、Token Filter組成的,那麼在自定義時這三個都是可以自定義的
自定義分詞必存在analyzer、tokenizer、char_filter、filter
這部分的定義都是需要在下面定義好規則,否則無法使用,詳細定義程式碼往下拉看完整版本即可
對這個配置不要死記硬背使用的多了自然就會記住
# 實戰自定義analyze
put kaka
{
"settings":{
"analysis":{
"analyzer":{
"my_custom_analyzer":{
"type":"custom",
"char_filter":[
"emoticons"
],
"tokenizer":"punctuation",
"filter":[
"lowercase",
"englist_stop"
]
}
},
"tokenizer":{
"punctuation":{
"type":"keyword"
}
},
"char_filter":{
"emoticons":{
"type":"mapping",
"mappings":[
"123 => Kaka",
"456 => xian tan"
]
}
},
"filter":{
"englist_stop":{
"type":"stop",
"stopwords":"_english_"
}
}
}
}
}
# 執行自定義的分詞
post /kaka/_analyze
{
"analyzer":"my_custom_analyzer",
"text":" 123 456"
}
# 返回結果,把字母大寫轉為小寫不做分詞
{
"tokens" : [
{
"token" : " kaka xian tan",
"start_offset" : 0,
"end_offset" : 8,
"type" : "word",
"position" : 0
}
]
}
十一、Index Template
在一個新索引新建並插入文件後,會使用預設的setting、mapping,如果你有設定settings、mappings會覆蓋預設的settings、mappings配置
# 建立索引並插入文件
post /kaka/_doc/1
{
"gongzhonghao":"123"
}
# 獲取settings、mappings
get /kaka
以下這個配置,就是預設配置
# 返回的settings、mappings
{
"kaka" : {
"aliases" : { },
"mappings" : {
"properties" : {
"gongzhonghao" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
},
"settings" : {
"index" : {
"creation_date" : "1642080577305",
"number_of_shards" : "1",
"number_of_replicas" : "1",
"uuid" : "JJWsGYcrTam0foEQxuZqGQ",
"version" : {
"created" : "7010099"
},
"provided_name" : "kaka"
}
}
}
}
接下來建立一個自己的模板
# 設定一個只要是test開頭的索引都能使用的模板,在這個模板中我們將字串中得數字也轉為了long型別,而非text
put /_template/kaka_tmp
{
"index_patterns":["test*"],
"order":1,
"settings":{
"number_of_shards":1,
"number_of_replicas":2
},
"mappings":{
# 讓時間不解析為date型別,返回是text型別
"date_detection":false,
# 讓雙引號下的數字解析為long型別,而非text型別
"numeric_detection":true
}
}
建立索引
post /test_kaka/_doc/1
{
"name":"123",
"date":"2022/01/13"
}
get /test_kaka
返回結果
{
"test_kaka" : {
"aliases" : { },
"mappings" : {
"date_detection" : false,
"numeric_detection" : true,
"properties" : {
"date" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"name" : {
"type" : "long"
}
}
},
"settings" : {
"index" : {
"creation_date" : "1642081053006",
"number_of_shards" : "1",
"number_of_replicas" : "2",
"uuid" : "iCcaa_8-TXuymhfzQi31yA",
"version" : {
"created" : "7010099"
},
"provided_name" : "test_kaka"
}
}
}
}
“堅持學習、堅持寫作、堅持分享是咔咔從業以來所秉持的信念。願文章在偌大的網際網路上能給你帶來一點幫助,我是咔咔,下期見。
”