Elasticsearch7學習筆記(上)
Elasticsearch7學習筆記(中)
Elasticsearch7學習筆記(下)
Elasticsearch7學習筆記(實戰(zhàn))
概述
ELK是Elasticsearch戈抄、Logstash划鸽、Kibana的簡稱裸诽,這三者是核心套件實現(xiàn)日志采集丈冬、分析埂蕊、展示蓄氧,但并非全部喉童。
Elasticsearch是實時全文搜索和分析引擎顿天,提供搜集牌废、分析畔规、存儲數(shù)據(jù)三大功能叁扫;是一套開放REST和JAVA API等結(jié)構(gòu)提供高效搜索功能莫绣,可擴展的分布式系統(tǒng)对室。它構(gòu)建于Apache Lucene搜索引擎庫之上。
Logstash是一個用來搜集么翰、分析浩嫌、過濾日志的工具码耐。它支持幾乎任何類型的日志骚腥,包括系統(tǒng)日志桦沉、錯誤日志和自定義應用程序日志。它可以從許多來源接收日志代芜,這些來源包括 syslog挤庇、消息傳遞(例如 RabbitMQ)和JMX嫡秕,它能夠以多種方式輸出數(shù)據(jù)昆咽,包括電子郵件掷酗、websockets和Elasticsearch泻轰。
Kibana是一個基于Web的圖形界面浮声,用于搜索泳挥、分析和可視化存儲在 Elasticsearch指標中的日志數(shù)據(jù)羡洁。它利用Elasticsearch的REST接口來檢索數(shù)據(jù)筑煮,不僅允許用戶創(chuàng)建他們自己的數(shù)據(jù)的定制儀表板視圖真仲,還允許他們以特殊的方式查詢和過濾數(shù)據(jù)秸应。
一软啼、Elasticsearch基礎
現(xiàn)在主流的搜索引擎大概就是:Lucene祸挪,Solr贿条,ElasticSearch整以。這里是對ElasticSearch的學習公黑。
1.1 Elasticsearch的功能
-
分布式的搜索引擎和數(shù)據(jù)分析引擎
搜索:百度凡蚜,網(wǎng)站的站內(nèi)搜索番刊,IT系統(tǒng)的檢索
數(shù)據(jù)分析:電商網(wǎng)站芹务,最近7天牙膏這種商品銷量排名前10的商家有哪些;新聞網(wǎng)站辆床,最近1個月訪問量排名前3的新聞版塊是哪些
分布式讼载,搜索咨堤,數(shù)據(jù)分析 -
全文檢索一喘,結(jié)構(gòu)化檢索凸克,數(shù)據(jù)分析
全文檢索:我想搜索商品名稱包含牙膏的商品萎战,select * from products where product_name like "%牙膏%"
結(jié)構(gòu)化檢索:我想搜索商品分類為日化用品的商品都有哪些,select * from products where category_id='日化用品'
部分匹配、自動完成览祖、搜索糾錯展蒂、搜索推薦
數(shù)據(jù)分析:我們分析每一個商品分類下有多少個商品锰悼,select category_id,count(*) from products group by category_id -
對海量數(shù)據(jù)進行近實時的處理
分布式:ES自動可以將海量數(shù)據(jù)分散到多臺服務器上去存儲和檢索
海聯(lián)數(shù)據(jù)的處理:分布式以后箕般,就可以采用大量的服務器去存儲和檢索數(shù)據(jù)丝里,自然而然就可以實現(xiàn)海量數(shù)據(jù)的處理了
近實時:檢索個數(shù)據(jù)要花費1小時(這就不要近實時杯聚,離線批處理幌绍,batch-processing)傀广;在秒級別對數(shù)據(jù)進行搜索和分析跟分布式/海量數(shù)據(jù)相反的:lucene主儡,單機應用丰捷,只能在單臺服務器上使用病往,最多只能處理單臺服務器可以處理的數(shù)據(jù)量
1.2 Elasticsearch的適用場景
國外
(1)維基百科停巷,類似百度百科畔勤,牙膏庆揪,牙膏的維基百科缸榛,全文檢索内颗,高亮均澳,搜索推薦
(2)The Guardian(國外新聞網(wǎng)站)负懦,類似搜狐新聞纸厉,用戶行為日志(點擊肯尺,瀏覽则吟,收藏氓仲,評論)+社交網(wǎng)絡數(shù)據(jù)(對某某新聞的相關(guān)看法)敬扛,數(shù)據(jù)分析啥箭,給到每篇新聞文章的作者急侥,讓他知道他的文章的公眾反饋(好坏怪,壞,熱門捉超,垃圾,鄙視况芒,崇拜)
(3)Stack Overflow(國外的程序異常討論論壇)绝骚,IT問題压汪,程序的報錯止剖,提交上去穿香,有人會跟你討論和回答皮获,全文檢索洒宝,搜索相關(guān)問題和答案待德,程序報錯了将宪,就會將報錯信息粘貼到里面去印蔗,搜索有沒有對應的答案
(4)GitHub(開源代碼管理)华嘹,搜索上千億行代碼
(5)電商網(wǎng)站耙厚,檢索商品
(6)日志數(shù)據(jù)分析薛躬,logstash采集日志,ES進行復雜的數(shù)據(jù)分析(ELK技術(shù)趴酣,elasticsearch+logstash+kibana)
(7)商品價格監(jiān)控網(wǎng)站岖寞,用戶設定某商品的價格閾值仗谆,當?shù)陀谠撻撝档臅r候胸私,發(fā)送通知消息給用戶阔涉,比如說訂閱牙膏的監(jiān)控瑰排,如果高露潔牙膏的家庭套裝低于50塊錢椭住,就通知我,我就去買
(8)BI系統(tǒng)些举,商業(yè)智能户魏,Business Intelligence叼丑。比如說有個大型商場集團李剖,BI,分析一下某某區(qū)域最近3年的用戶消費金額的趨勢以及用戶群體的組成構(gòu)成贞铣,產(chǎn)出相關(guān)的數(shù)張報表,**區(qū)酱畅,最近3年纺酸,每年消費金額呈現(xiàn)100%的增長,而且用戶群體85%是高級白領(lǐng)樊诺,開一個新商場词爬。ES執(zhí)行數(shù)據(jù)分析和挖掘,Kibana進行數(shù)據(jù)可視化
國內(nèi)
(9)國內(nèi):站內(nèi)搜索(電商权均,招聘顿膨,門戶,等等)虽惭,IT系統(tǒng)搜索(OA,CRM蛇尚,ERP芽唇,等等),數(shù)據(jù)分析(ES熱門的一個使用場景)
1.3 elasticsearch的核心概念
Elasticsearch 數(shù)據(jù)庫
-----------------------------------------
Document 行
Type 表(在7.x以后已經(jīng)移除了取劫,默認為_doc; 在6.x以后一個索引只能有一個type了匆笤,在5.x以前一個索引可以有多個type)
Index 庫
(1)Near Realtime(NRT):近實時,兩個意思谱邪,從寫入數(shù)據(jù)到數(shù)據(jù)可以被搜索到有一個小延遲(大概1秒)炮捧;基于es執(zhí)行搜索和分析可以達到秒級
(2)Cluster:集群,包含多個節(jié)點惦银,每個節(jié)點屬于哪個集群是通過一個配置(集群名稱咆课,默認是elasticsearch)來決定的末誓,對于中小型應用來說,剛開始一個集群就一個節(jié)點很正常
(3)Node:節(jié)點书蚪,集群中的一個節(jié)點喇澡,節(jié)點也有一個名稱(默認是隨機分配的),節(jié)點名稱很重要(在執(zhí)行運維管理操作的時候)殊校,默認節(jié)點會去加入一個名稱為“elasticsearch”的集群晴玖,如果直接啟動一堆節(jié)點,那么它們會自動組成一個elasticsearch集群为流,當然一個節(jié)點也可以組成一個elasticsearch集群
(4)Document&field:文檔呕屎,es中的最小數(shù)據(jù)單元,一個document可以是一條客戶數(shù)據(jù)敬察,一條商品分類數(shù)據(jù)秀睛,一條訂單數(shù)據(jù),通常用JSON數(shù)據(jù)結(jié)構(gòu)表示莲祸,每個index下的type中琅催,都可以去存儲多個document。一個document里面有多個field虫给,每個field就是一個數(shù)據(jù)字段藤抡。
(5)Index:索引,包含一堆有相似結(jié)構(gòu)的文檔數(shù)據(jù)抹估,比如可以有一個客戶索引缠黍,商品分類索引,訂單索引药蜻,索引有一個名稱瓷式。一個index包含很多document,一個index就代表了一類類似的或者相同的document语泽。比如說建立一個product index贸典,商品索引,里面可能就存放了所有的商品數(shù)據(jù)踱卵,所有的商品document廊驼。
(6)shard:單臺機器無法存儲大量數(shù)據(jù),es可以將一個索引中的數(shù)據(jù)切分為多個shard惋砂,分布在多臺服務器上存儲妒挎。有了shard就可以橫向擴展,存儲更多數(shù)據(jù)西饵,讓搜索和分析等操作分布到多臺服務器上去執(zhí)行酝掩,提升吞吐量和性能。每個shard都是一個lucene index眷柔。
(7)replica:任何一個服務器隨時可能故障或宕機期虾,此時shard可能就會丟失原朝,因此可以為每個shard創(chuàng)建多個replica副本。replica可以在shard故障時提供備用服務镶苞,保證數(shù)據(jù)不丟失喳坠,多個replica還可以提升搜索操作的吞吐量和性能。primary shard(建立索引時一次設置宾尚,不能修改,默認5個)谢澈,replica shard(隨時修改數(shù)量煌贴,默認1個),默認每個索引10個shard锥忿,5個primary shard牛郑,5個replica shard,最小的高可用配置敬鬓,是2臺服務器淹朋。
1.4 使用docker安裝Elasticsearch
-
拉取docker鏡像,由于國內(nèi)網(wǎng)絡原因钉答,速度可能會比較慢或者無法下載础芍;可以直接安裝對應系統(tǒng)的安裝包進行安裝即可,基本都是解壓運行即可数尿。
docker pull elasticsearch:7.8.0
鏡像下載慢可以配置國內(nèi)的加速
編輯編輯/etc/docker/daemon.json
文件
vi /etc/docker/daemon.json
添加鏡像加速地址(下面這個是網(wǎng)易的加速地址):
{
"registry-mirrors": ["http://hub-mirror.c.163.com"]
}
也可以使用申請阿里云容器鏡像服務ACR[https://www.aliyun.com/product/acr]仑性;申請成功后點擊管理控制臺,選擇鏡像中心->鏡像加速獲取地址右蹦。
重啟docker
systemctl daemon-reload
systemctl restart docker
- 創(chuàng)建elasticsearch容器诊杆,并啟動(這里使用單機版)
docker run -d --name es7 -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.8.0
- 訪問
http://192.168.1.6:9200/
如果正常返回則說明成功,類似:
{
"name" : "074c8527cecd",
"cluster_name" : "docker-cluster",
"cluster_uuid" : "YBNpiQm8Qxmd0ma7j-1uGw",
"version" : {
"number" : "7.8.0",
"build_flavor" : "default",
"build_type" : "docker",
"build_hash" : "757314695644ea9a1dc2fecd26d1a43856725e65",
"build_date" : "2020-06-14T19:35:50.234439Z",
"build_snapshot" : false,
"lucene_version" : "8.5.1",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
二何陆、Kibana
kibana的界面可以很方便的查看elasticsearch的信息晨汹,也可以做圖表、指標等贷盲。同時提供控制臺命令操作elasticsearch淘这。
使用docker安裝kibana
# 拉取kibana的鏡像
docker pull kibana:7.8.0
# 啟動kibana
docker run -d --name kibana --link 已經(jīng)啟動的elasticsearch的容器ID或者是名字:elasticsearch -p 5601:5601 kibana:7.8.0
# 例如
docker run -d --name kibana --link es7:elasticsearch -p 5601:5601 kibana:7.8.0
通過http://192.168.111.44:5601
訪問kibana
如果需要中文界面在kibana.yml文件中添加
i18n.locale: "zh-CN"
配置重啟即可
通過kibana的Console來做elasticsearch的crud和相關(guān)配置
elasticsearch集群狀態(tài)
GET _cat/health?v
green:每個索引的primary shard和replica shard都是active狀態(tài)的
yellow:每個索引的primary shard都是active狀態(tài)的,但是部分replica shard不是active狀態(tài)巩剖,處于不可用的狀態(tài)
red:不是所有索引的primary shard都是active狀態(tài)的慨灭,部分索引有數(shù)據(jù)丟失了
后面加v是為了打印出更多的信息
索引相關(guān)操作
# 查詢所有索引
GET _cat/indices?v
# 創(chuàng)建索引
PUT /索引名稱?pretty
# 刪除索引
DELETE /索引名稱
向elasticsearch中添加和修改數(shù)據(jù);
語法, 使用POST或者PUT都可以,存在則更新否則創(chuàng)建球及;
區(qū)別在于沒有加ID值時(沒有ID會自動生成)氧骤,只能用POST表示創(chuàng)建;
需要注意的是使用PUT做更新時吃引,其實是直接覆蓋筹陵,因此需要帶上所有的數(shù)據(jù)刽锤;
POST /索引名稱/_doc
POST /索引名稱/_create
POST /索引名稱/_doc/數(shù)據(jù)的id值
POST /索引名稱/_create/數(shù)據(jù)的id值
PUT /索引名稱/_doc/數(shù)據(jù)的id值
PUT /索引名稱/_create/數(shù)據(jù)的id值
只更新指定字段的值:
POST/索引名稱/_update/數(shù)據(jù)的ID值 {
"doc":{
// 更新內(nèi)容
}
}
查詢數(shù)據(jù)
# 查詢所有
GET /索引名稱/_search
# 根據(jù)ID查詢
GET /索引名稱/_doc/數(shù)據(jù)的id值
刪除數(shù)據(jù)
DELETE /索引名稱/_doc/數(shù)據(jù)的id值
刪除使用的邏輯刪除,之后會統(tǒng)一進行物理刪除
示例
# 添加或更新替換
POST /ecommerce/_doc/1
{
"name":"小米手機",
"desc":"支持5G朦佩、全面屏6.4",
"price":3000,
"producer":"小米",
"tags":["mobile","5G"]
}
# 添加或更新替換
PUT /ecommerce/_doc/2
{
"name":"華為MacBook",
"desc":"支持5G并思、全面屏15.2寸",
"price":8000,
"producer":"Huawei",
"tags":["筆記本電腦","huawei"]
}
# 添加或更新替換
POST /ecommerce/_create/3
{
"name":"華為P40 pro",
"desc":"支持5G、超清攝像",
"price":12000,
"producer":"Huawei 成都",
"tags":["mobile","huawei","5G"]
}
# 添加
POST /ecommerce/_doc
{
"name":"Ipad mini 5",
"desc":"7.9英寸",
"price":4000,
"producer":"apple",
"tags":["筆記本電腦","apple"]
}
# 更新
POST /ecommerce/_update/1
{
"doc": {
"price":2000
}
}
# 查詢
GET /ecommerce/_search
GET /ecommerce/_doc/1
# 刪除
DELETE /ecommerce/_doc/4
elasticsearch查詢語句示例
query string search
query string search
就是將查詢條件放到http的參數(shù)上
1语稠、查詢?nèi)?/p>
GET /ecommerce/_search
返回字段說明:
took:耗費了幾毫秒
timed_out:是否超時
_shards:數(shù)據(jù)拆成幾個分片宋彼,所以對于搜索請求,會打到所有的primary shard(或者是它的某個replica shard也可以)
hits.total:查詢結(jié)果的數(shù)量仙畦,即幾個document
hits.max_score:score的含義输涕,就是document對于一個search的相關(guān)度的匹配分數(shù),越相關(guān)慨畸,就越匹配莱坎,分數(shù)也高
hits.hits:包含了匹配搜索的document的詳細數(shù)據(jù)
2、查詢名稱包含華為
的商品,并且按照售價降序排序
GET /ecommerce/_search?q=name:華為&sort=price:desc
3寸士、只返回name檐什、price字段
GET /ecommerce/_search?_source=name,price
query DSL
DSL:Domain Specified Language,特定領(lǐng)域的語言
http request body:請求體弱卡,可以用json的格式來構(gòu)建查詢語法乃正,
比較方便,可以構(gòu)建各種復雜的語法婶博,比query string search肯定強大多了
查詢所有match_all
GET /ecommerce/_search
{
"query": { "match_all": {} }
}
查詢名稱包含華為
的商品烫葬,同時按照價格降序排序
GET /ecommerce/_search
{
"query": {
"match": {
"name": "華為"
}
}
, "sort": [
{
"price": {
"order": "desc"
}
}
]
}
分頁查詢
GET /ecommerce/_search
{
"query": {
"match_all": {}
},
"from": 2,
"size": 2
}
from 從第幾條開始,起始為0
size 返回多少條記錄
指定返回的字段
GET /ecommerce/_search
{
"query": {
"match_all": {}
},
"_source": ["name", "price"]
}
query filter
對數(shù)據(jù)進行過濾
搜索商品名稱包含華為
凡蜻,而且售價大于8000元的商品
GET /ecommerce/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"name": "華為"
}
}
],
"filter": [
{
"range": {
"price": {
"gt": 8000
}
}
}
]
}
}
}
或者
GET /ecommerce/_search
{
"query": {
"bool": {
"must": {
"match": {
"name": "華為"
}
}
,
"filter": {
"range": {
"price": {
"gt": 8000
}
}
}
}
}
}
bool 里面可以寫多個條件
full-text search(全文檢索)
全文檢索會將輸入的搜索串拆解開來搭综,去倒排索引里面去一一匹配,只要能匹配上任意一個拆解后的單詞划栓,就可以作為結(jié)果返回
GET /ecommerce/_search
{
"query":{
"match": {
"producer": "Huawei 成都"
}
}
}
phrase search(短語搜索)
跟全文檢索相對應相反兑巾,phrase search,要求輸入的搜索串忠荞,必須在指定的字段文本中蒋歌,完全包含一模一樣的,才可以算匹配委煤,才能作為結(jié)果返回
GET /ecommerce/_search
{
"query": {
"match_phrase": {
"producer": "Huawei 成都"
}
}
}
highlight search(高亮搜索結(jié)果)
高亮搜索結(jié)果就是將匹配的字段做標識堂油,就像百度搜索中那些匹配的內(nèi)容是紅色顯示
GET /ecommerce/_search
{
"query": {
"match": {
"producer": "Huawei"
}
},
"highlight": {
"fields": {
"producer": {}
}
}
}
聚合:計算每個tag下的商品數(shù)量
GET /ecommerce/_search
{
"size": 0,
"aggs": {
"group_by_tags":{
"terms": {
"field": "tags"
}
}
}
}
group_by_tags 是隨意取的一個名字,待會的查詢統(tǒng)計結(jié)果會放到這個字段中
加size是不返回原始數(shù)據(jù)
上面那樣操作會報錯碧绞,需要先執(zhí)行下面的語句府框,更新tags字段的fielddata屬性設置為true
PUT /ecommerce/_mapping
{
"properties":{
"tags":{
"type":"text",
"fielddata":true
}
}
}
聚合:對名稱中包含yagao的商品,計算每個tag下的商品數(shù)量
GET /ecommerce/_search
{
"size": 0,
"query": {
"match": {
"name": "華為"
}
},
"aggs": {
"all_tags": {
"terms": {
"field": "tags"
}
}
}
}
先執(zhí)行query條件查詢讥邻,然后對結(jié)果做aggs聚合處理
聚合:計算每個tag下的商品的平均價格(先分組再平均)
GET /ecommerce/_search
{
"size": 0,
"aggs": {
"group_by_tags": {
"terms": {
"field": "tags"
},
"aggs": {
"avg_price": {
"avg": {
"field": "price"
}
}
}
}
}
}
計算每個tag下的商品的平均價格迫靖,并且按照平均價格降序排序
GET /ecommerce/_search
{
"size": 0
, "aggs": {
"all_tags": {
"terms": {
"field": "tags", "order": {
"avg_price": "desc"
}
},
"aggs": {
"avg_price": {
"avg": {
"field": "price"
}
}
}
}
}
}
按照指定的價格范圍區(qū)間進行分組院峡,然后在每組內(nèi)再按照tag進行分組,最后再計算每組的平均價格
GET /ecommerce/_search
{
"size": 0,
"aggs": {
"group_by_price": {
"range": {
"field": "price",
"ranges": [
{
"from": 0,
"to": 5000
},
{
"from": 6000
}
]
},
"aggs": {
"group_by_tags": {
"terms": {
"field": "tags"
},
"aggs": {
"avg_price": {
"avg": {
"field": "price"
}
}
}
}
}
}
}
}
cerebo
這個是個es的監(jiān)控軟件系宜,可以很方便的查詢es集群的分片等情況照激,能集中管理alias和index template;在kibana中需要使用命令才可以實現(xiàn)盹牧,可以根據(jù)自己需要來安裝俩垃。
拉取鏡像:
docker pull yannart/cerebro
啟動容器:
docker run -d -p 9000:9000 --name cerebro yannart/cerebro:latest
瀏覽器訪問9000
http://ip:9000
直接輸入es的連接地址即可,如:http://192.168.6.2:9200
在一臺機器上導致連接失敗的問題
由于資源有限汰寓,上面這些組件全部都放在了一機器上導致無法訪問口柳,需要打開防火墻開放端口才可以;
查看防火墻狀態(tài)
systemctl status firewalld
重啟防火墻
systemctl restart firewalld.service
查看已經(jīng)開放的端口
firewall-cmd --zone=public --list-ports
開放如下端口(第二個可選)
firewall-cmd --zone=public --add-port=9200/tcp --permanent && firewall-cmd --reload
firewall-cmd --zone=public --add-port=9300/tcp --permanent && firewall-cmd --reload
firewall-cmd --zone=public --add-port=5601/tcp --permanent && firewall-cmd --reload
firewall-cmd --zone=public --add-port=9000/tcp --permanent && firewall-cmd --reload
這樣容器間就可以相互訪問了(開啟防火墻后可能需要重啟docker服務才行)
三踩寇、Elasticsearch 的分布式集群
shard&replica機制
(1)index包含多個shard
(2)每個shard都是一個最小工作單元啄清,承載部分數(shù)據(jù)六水,lucene實例俺孙,完整的建立索引和處理請求的能力
(3)增減節(jié)點時,shard會自動在nodes中負載均衡
(4)primary shard和replica shard掷贾,每個document肯定只存在于某一個primary shard以及其對應的replica shard中睛榄,不可能存在于多個primary shard
(5)replica shard是primary shard的副本,負責容錯想帅,以及承擔讀請求負載
(6)primary shard的數(shù)量在創(chuàng)建索引的時候就固定了场靴,replica shard的數(shù)量可以隨時修改
(7)primary shard的默認數(shù)量是5,replica默認是1港准,默認有10個shard旨剥,5個primary shard,5個replica shard
(8)primary shard不能和自己的replica shard放在同一個節(jié)點上(否則節(jié)點宕機浅缸,primary shard和副本都丟失轨帜,起不到容錯的作用),但是可以和其他primary shard的replica shard放在同一個節(jié)點上
(9)相同primary shard的replica shard不能放在同一個節(jié)點上衩椒;(節(jié)點宕機時蚌父,replica shard副本都丟失,起不到容錯的作用)
單node環(huán)境下創(chuàng)建index
(1)單node環(huán)境下毛萌,創(chuàng)建一個index苟弛,有3個primary shard,3個replica shard
(2)集群status是yellow
(3)這個時候阁将,只會將3個primary shard分配到僅有的一個node上去膏秫,另外3個replica shard是無法分配的
(4)集群可以正常工作,但是一旦出現(xiàn)節(jié)點宕機做盅,數(shù)據(jù)全部丟失荔睹,而且集群不可用狸演,無法承接任何請求
四、Elasticsearch內(nèi)部相關(guān)實現(xiàn)
并發(fā)數(shù)據(jù)修改控制
Elasticsearch內(nèi)部是多線程異步并發(fā)的進行修改(即可能出現(xiàn)后修改的先處理)僻他,采用version進行樂觀鎖宵距;
具體原理:Elasticsearch每次執(zhí)行更新和刪除操作成功時,它的version都會自動加1吨拗,
每次執(zhí)行更新刪除時會帶上版本號满哪,如果版本號不一致,則會放棄此次操作劝篷;
這樣就保證了后修改的先執(zhí)行的情況能夠正常處理哨鸭,不會被先修改的覆蓋掉。
示例:在更新的時候帶上版本號參數(shù)
POST /ecommerce/_update/2?version=3
{
"doc":{
"tags":["laptop ", "Huawei"]
}
}
當版本號version不匹配的時候會更新失敗
使用external version來進行樂觀鎖并發(fā)控制
es提供了一個feature娇妓,就是說像鸡,你可以不用它提供的內(nèi)部_version版本號來進行并發(fā)控制,可以基于你自己維護的一個版本號來進行并發(fā)控制哈恰。
舉個列子只估,假如你的數(shù)據(jù)在mysql里也有一份,然后你的應用系統(tǒng)本身就維護了一個版本號着绷,無論是什么自己生成的蛔钙,程序控制的。
這個時候荠医,你進行樂觀鎖并發(fā)控制的時候吁脱,可能并不是想要用es內(nèi)部的_version來進行控制,而是用你自己維護的那個version來進行控制彬向。
PUT /ecommerce/_doc/1?version=2&version_type=external
{
"name" : "小米10Pro",
"desc" : "支持5G兼贡、全面屏6.4",
"price" : 3000,
"producer" : "小米",
"tags" : [
"xiaomi",
"mobile",
"5G"
]
}
在后面多加一個
version_type=external
參數(shù),只有version版本比當前ES維護的版本號大就可以更新成功
partial update說明
語法(url地址后面可以加版本號?version=1):
POST /索引名稱/_update/ID值
{
"doc":{
// 更新字段信息
}
}
使用partial update進行更新其實際執(zhí)行過程如下:
- 內(nèi)部先獲取document娃胆;
- 將傳過來的field更新到document的json中去遍希;
- 將原來的document標記為刪除狀態(tài);
- 將修改后的新的document創(chuàng)建出來缕棵;
實際上和傳統(tǒng)的全量替換幾乎一樣孵班。
如果document不存在會報錯
同時partial update將自動執(zhí)行基于version的樂觀鎖并發(fā)控制
設置在發(fā)送沖突時進行重試的次數(shù)
POST /ecommerce/_update/1?retry_on_conflict=2
{
"doc": {
"price":3000
}
}
優(yōu)點
- 所有查詢、修改和寫回操作都發(fā)生在es的一個shard內(nèi)部招驴,幾乎避免了所有的網(wǎng)絡數(shù)據(jù)傳輸開銷篙程,提升性能;
- 減少了查詢和修改的時間間隔别厘,能夠有效的減少并發(fā)的沖突的情況虱饿;(因為其內(nèi)部操作幾乎在毫秒級別)
示例
POST /ecommerce/_update/1
{
"doc":{
"name" : "小米10"
}
}
es的腳本支持:groovy
使用內(nèi)置腳本來做累加操作
將price加1
POST /ecommerce/_update/1
{
"script": "ctx._source.price+=1"
}
外置腳本
這個相當于關(guān)系型數(shù)據(jù)庫的存儲過程,將需要執(zhí)行的腳本放到es的config/scripts
目錄下
如在config/scripts
目錄下創(chuàng)建一個名為add-price.groovy
文件,在里面寫入如下腳本:
ctx._source.price+=add_price
執(zhí)行這個腳本:
POST /ecommerce/_update/1
{
"script": {
"lang": "groovy",
"file": "add-price",
"params": {
"add_price":1
}
}
}
示例刪除document的腳本
在config/scripts
目錄下創(chuàng)建一個名為del-doc.groovy
文件氮发,在里面寫入如下腳本:
ctx.op = ctx._source.price>price?'delete':'none'
執(zhí)行腳本
POST /ecommerce/_update/1
{
"script": {
"lang": "groovy",
"file": "del-doc",
"params": {
"price":5000
}
}
}
upsert的使用
解決當在執(zhí)行更新時document不存在導致更新失敗的問題渴肉。
POST /ecommerce/_update/1
{
"script": "ctx._source.price+=1",
"upsert": {
"price":0,
"tags":[]
}
}
upsert就是沒有的時候?qū)ocument進行初始化
_mget批量查詢
普通的查詢方式只能一條一條的查詢,使用mget可以實現(xiàn)批量查詢爽冕,減少網(wǎng)絡開銷
查詢ID為1和2的數(shù)據(jù)
不同的index
GET /_mget
{
"docs":[
{
"_index":"ecommerce",
"_id":1
},
{
"_index":"goods",
"_id":2
}
]
}
同一個index
GET /ecommerce/_mget
{
"docs":[
{
"_id":1
},
{
"_id":2
}
]
}
同一個index且相同的filed
GET /ecommerce/_mget
{
"ids":[1,2]
}
對返回的source字段進行過濾
GET /ecommerce/_mget
{
"docs":[
{
"_id":1,
"_source":["price","name"]
},
{
"_id":2,
"_source":"price"
},
{
"_id":3,
"_source":false
}
]
}
注意直接用ids來查詢時不能進行字段過濾
_bulk批量增刪改
create:創(chuàng)建
delete:刪除
update:更新
POST /_bulk
{"delete":{"_index":"ecommerce","_id":3}}
{"create":{"_index":"ecommerce","_id":3}}
{"price":5000}
{"update":{"_index":"ecommerce","_id":3}}
{"doc":{"price":6000}}
一條語句不能有換行這些仇祭,直接一行
在create之后可以添加需要添加的屬性
update的更新屬性需要加doc
如果在一個index中可以不寫index,直接跟在url上即可
POST /ecommerce/_bulk
{"delete":{"_id":3}}
{"create":{"_id":3}}
{"price":5000}
{"update":{"_id":3}}
{"doc":{"price":6000}}
_bulk在執(zhí)行的時候颈畸,如果其中有一條語句執(zhí)行失敗乌奇,不會影響其他的執(zhí)行,會在返回結(jié)果中將異常提示返回
bulk size最佳大小
bulk request會加載到內(nèi)存里眯娱,如果太大的話礁苗,性能反而會下降,因此需要反復嘗試一個最佳的bulk size徙缴。
一般從1000到5000條數(shù)據(jù)開始试伙,嘗試逐漸增加。另外于样,如果看大小的話疏叨,最好是在5~15MB之間。
什么是distributed document store百宇?
圍繞著document在操作考廉,其實就是把es當成了一個NoSQL存儲引擎秘豹,一個可以存儲文檔類型數(shù)據(jù)的存儲系統(tǒng)携御,操作里面的document。
適合的的應用程序類型
(1)數(shù)據(jù)量較大既绕,es的分布式本質(zhì)啄刹,可以幫助你快速進行擴容,承載大量數(shù)據(jù)
(2)數(shù)據(jù)結(jié)構(gòu)靈活多變凄贩,隨時可能會變化誓军,而且數(shù)據(jù)結(jié)構(gòu)之間的關(guān)系,非常復雜疲扎,如果我們用傳統(tǒng)數(shù)據(jù)庫昵时,那是不是很坑,因為要面臨大量的表
(3)對數(shù)據(jù)的相關(guān)操作椒丧,較為簡單壹甥,比如就是一些簡單的增刪改查,用我們之前講解的那些document操作就可以搞定
(4)NoSQL數(shù)據(jù)庫壶熏,適用的也是類似于上面的這種場景
document數(shù)據(jù)路由原理
(1)document路由到shard上是什么意思句柠?
一個index的數(shù)據(jù)會被分為多片,每片都在一個shard中,因此一個document只能存在一個shard中溯职;
當有一個document需要操作時精盅,es就需要知道這個document是放在index的那個shard上的。
這個過程就稱之為document的數(shù)據(jù)路由谜酒。
(2)路由算法:shard = hash(routing) % number_of_primary_shards
舉個例子來簡要說明哈這個算法:
一個index有3個primary shard(分別為P0叹俏,P1,P2)僻族,每次增刪改查一個document的時候她肯,都會帶過來一個routing number,
默認就是這個document的_id(可能是手動指定鹰贵,也可能是自動生成)routing = _id晴氨,假設_id=1;將這個routing值傳入一個hash函數(shù)中碉输,產(chǎn)出一個routing值的hash值籽前;
然后將hash函數(shù)產(chǎn)出的值對這個index的primary shard的數(shù)量求余數(shù),根據(jù)這個余數(shù)的值決定document放在那個shard上
決定一個document在哪個shard上敷钾,最重要的一個值就是routing值枝哄,默認是_id,也可以手動指定阻荒,保證相同的routing值债鸡,每次過來朴肺,從hash函數(shù)中,產(chǎn)出的hash值一定是相同的;
這也是為什么ES啟動后設置好primary_shards數(shù)量之后稻艰,primary_shards的數(shù)量不能再更改了的原因
document增刪改內(nèi)部原理
(1)客戶端選擇一個node發(fā)送請求過去汛闸,這個node就是coordinating node(協(xié)調(diào)節(jié)點)
(2)coordinating node卫袒,對document進行路由叁执,將請求轉(zhuǎn)發(fā)給對應的node(有primary shard)
(3)實際的node上的primary shard處理請求,然后將數(shù)據(jù)同步到replica node
(4)coordinating node油猫,如果發(fā)現(xiàn)primary node和所有replica node都搞定之后稠茂,就返回響應結(jié)果給客戶端
寫一致性原理以及quorum機制剖析
consistency,one(primary shard)情妖,all(all shard)睬关,quorum(default)
我們在發(fā)送任何一個增刪改操作的時候,比如說put /index/_doc/id
毡证,都可以帶上一個consistency
參數(shù)电爹,指明我們想要的寫一致性是什么?
put /index/_doc/id?consistency=quorum
one:要求我們這個寫操作情竹,只要有一個primary shard是active活躍可用的藐不,就可以執(zhí)行
all:要求我們這個寫操作匀哄,必須所有的primary shard和replica shard都是活躍的,才可以執(zhí)行這個寫操作
quorum:默認的值雏蛮,要求所有的shard中涎嚼,必須是大部分的shard都是活躍的,可用的挑秉,才可以執(zhí)行這個寫操作
quorum機制法梯,寫之前必須確保大多數(shù)shard都可用(也就是半數(shù)以上)
計算公式:
quroum = int( (primary + number_of_replicas) / 2 ) + 1,當number_of_replicas>1時才生效犀概;active狀態(tài)的的shard數(shù)>=quroum才可以執(zhí)行
舉個例子:
3個primary shard立哑,number_of_replicas=1,總共有3 + 3 * 1 = 6個shard
quorum = int( (3 + 1) / 2 ) + 1 = 3
所以姻灶,要求6個shard中至少有3個shard是active狀態(tài)的铛绰,才可以執(zhí)行寫操作
如果節(jié)點數(shù)少于quorum數(shù)量,可能導致quorum不齊全产喉,進而導致無法執(zhí)行任何寫操作
如下2個例子:
例子1:3個primary shard捂掰,replica=1,要求至少3個shard是active曾沈,3個shard按照之前學習的shard&replica機制这嚣,必須在不同的節(jié)點上,如果說只有1臺機器的話塞俱,是不是有可能出現(xiàn)說姐帚,3個shard都沒法分配齊全,此時就可能會出現(xiàn)寫操作無法執(zhí)行的情況
例子2:1個primary shard障涯,replica=3罐旗,quorum=((1 + 3) / 2) + 1 = 3,要求1個primary shard + 3個replica shard = 4個shard像樊,其中必須有3個shard是要處于active狀態(tài)的尤莺。如果這個時候只有2臺機器的話旅敷,會出現(xiàn)什么情況呢生棍?
因此es提供了一種特殊的處理場景,當number_of_replicas>1時才生效媳谁,因為假如說涂滴,就一個primary shard,replica=1晴音,此時就2個shard
(1 + 1 / 2) + 1 = 2柔纵,要求必須有2個shard是活躍的,但是可能就1個node锤躁,此時就1個shard是活躍的搁料,如果你不特殊處理的話,導致我們的單節(jié)點集群就無法工作
quorum不齊全時,wait郭计,默認1分鐘霸琴,timeout,100昭伸,30s
等待期間梧乘,期望活躍的shard數(shù)量可以增加,最后實在不行庐杨,就會timeout
我們其實可以在寫操作的時候选调,加一個timeout參數(shù),比如說put /index/type/id?timeout=30
灵份,這個就是自己去設定quorum不滿足條件的時候仁堪,es的timeout時長,可以縮短填渠,也可以增長
document查詢內(nèi)部原理
- 客戶端發(fā)送請求到任意一個node枝笨,成為coordinate node
- coordinate node對document進行路由,將請求轉(zhuǎn)發(fā)到對應的node揭蜒,此時會使用round-robin隨機輪詢算法横浑,在primary shard以及其所有replica中隨機選擇一個,讓讀請求負載均衡
- 接收請求的node返回document給coordinate node
- coordinate node返回document給客戶端
- 特殊情況:document如果還在建立索引過程中屉更,可能只有primary shard有徙融,任何一個replica shard都沒有,此時可能會導致無法讀取到document瑰谜,
但是document完成索引建立之后欺冀,primary shard和replica shard就都有了
bulk api的奇特json格式與底層性能優(yōu)化關(guān)系
bulk api奇特的json格式
{"action": {"meta"}}\n
{"data"}\n
{"action": {"meta"}}\n
{"data"}\n
1、bulk中的每個操作都可能要轉(zhuǎn)發(fā)到不同的node的shard去執(zhí)行
2萨脑、如果采用比較良好的json數(shù)組格式
允許任意的換行隐轩,整個可讀性非常棒,讀起來很爽渤早,es拿到那種標準格式的json串以后职车,要按照下述流程去進行處理
- 將json數(shù)組解析為JSONArray對象,這個時候鹊杖,整個數(shù)據(jù)悴灵,就會在內(nèi)存中出現(xiàn)一份一模一樣的拷貝,一份數(shù)據(jù)是json文本骂蓖,一份數(shù)據(jù)是JSONArray對象
- 解析json數(shù)組里的每個json积瞒,對每個請求中的document進行路由
- 為路由到同一個shard上的多個請求,創(chuàng)建一個請求數(shù)組
- 將這個請求數(shù)組序列化
- 將序列化后的請求數(shù)組發(fā)送到對應的節(jié)點上去
3登下、耗費更多內(nèi)存茫孔,更多的jvm gc開銷
占用更多的內(nèi)存可能就會積壓其他請求的內(nèi)存使用量叮喳,比如說最重要的搜索請求,分析請求缰贝,等等嘲更,此時就可能會導致其他請求的性能急速下降
另外的話,占用內(nèi)存更多揩瞪,就會導致java虛擬機的垃圾回收次數(shù)更多赋朦,更頻繁,每次要回收的垃圾對象更多李破,耗費的時間更多宠哄,導致es的java虛擬機停止工作線程的時間更多
假如:一個bulk size的請求為10M,共計100個請求就是1GB的內(nèi)存占用嗤攻,假設轉(zhuǎn)為json對象后為2GB毛嫉,如果請求數(shù)量更多,那么消耗的內(nèi)存就就更多了妇菱,同時Java虛擬機的垃圾回收也會更加的耗時承粤,導致系統(tǒng)性能下降。
4闯团、使用現(xiàn)在的奇特格式的優(yōu)點
- 不用將其轉(zhuǎn)換為json對象辛臊,不會出現(xiàn)內(nèi)存中的相同數(shù)據(jù)的拷貝,直接按照換行符切割json
- 對每兩個一組的json房交,讀取meta彻舰,進行document路由
- 直接將對應的json發(fā)送到node上去
5、最大的優(yōu)勢在于候味,不需要將json數(shù)組解析為一個JSONArray對象形成一份大數(shù)據(jù)的拷貝刃唤,浪費內(nèi)存空間,這樣可以盡可能地保證性能
五白群、搜索引擎
5.1 search結(jié)果解析(search timeout機制說明)
took:整個搜索請求花費了多少毫秒
hits.total:本次搜索尚胞,返回了幾條結(jié)果
hits.max_score:本次搜索的所有結(jié)果中,最大的相關(guān)度分數(shù)是多少帜慢,每一條document對于search的相關(guān)度笼裳,_score分數(shù)越大,排位越靠前
hits.hits:默認查詢前10條數(shù)據(jù)崖堤,完整數(shù)據(jù)侍咱,_score降序排序
timeout:默認無timeout,latency平衡completeness密幔,手動指定timeout,timeout查詢執(zhí)行機制
shards:shards fail的條件(primary和replica全部掛掉)撩轰,不影響其他shard胯甩。默認情況下來說昧廷,一個搜索請求,會打到一個index的所有primary shard上去偎箫,每個primary shard都可能會有一個或多個replica shard木柬,所以請求也可以到primary shard的其中一個replica shard上去。
帶上超時參數(shù):timeout=10ms淹办,timeout=1s眉枕,timeout=1m
GET /_search?timeout=10m
5.2 multi-index和multi-type搜索模式解析以及搜索原理
multi-index和multi-type搜索模式
如何一次性搜索多個index和多個type下的數(shù)據(jù)
GET /_search: 所有索引,所有type下的所有數(shù)據(jù)都搜索出來
GET /index1/_search: 指定一個index怜森,搜索其下所有的數(shù)據(jù)
GET /index1,index2/_search: 同時搜索兩個index下的數(shù)據(jù)
GET /*1,*2/_search: 按照通配符去匹配多個索引
GET /_all/_search 可以代表搜索所有index下的數(shù)據(jù)
也可以加刪除type屬性速挑,但是es
簡單的搜索原理
客戶端發(fā)送一個請求,會將請求分發(fā)到所有的primary shard上執(zhí)行副硅,因為每一個shard上都包含部分數(shù)據(jù)姥宝,所有每一個shard上都可能包含搜索請求的結(jié)果;
如果primary shard有 replica shard恐疲,那么請求也會發(fā)送到replica shard上去處理
5.3 分頁搜索以及deep paging性能問題
使用es進行分頁搜索的語法
size腊满,from
GET /_search?size=10
GET /_search?size=10&from=0
GET /_search?size=10&from=20
deep paging
搜索很深就是deep paging;會很耗費性能培己,應當盡量避免碳蛋。比如查詢臨近最后一頁的數(shù)據(jù),而數(shù)據(jù)在各個分片上省咨,最后需要將各個分片返回的數(shù)據(jù)進行綜合處理疮蹦,每個分片實際返回數(shù)據(jù)不是每頁的條數(shù)。
5.4 快速掌握query string search語法以及_all metadata
query string基礎語法
GET /demo_index/_search?q=test_field:test
GET /demo_index/_search?q=+test_field:test
GET /demo_index/_search?q=-test_field:test
使用+號和沒有+號是一樣茸炒,表示包含指定的關(guān)鍵詞愕乎;-號表示不含
_all metadata的原理和作用
# 匹配包含test的數(shù)據(jù)
GET /demo_index/_search?q=test
直接可以搜索所有的field,任意一個field包含指定的關(guān)鍵字就可以搜索出來壁公。我們在進行中搜索的時候感论,不是對document中的每一個field都進行一次搜索;
es中的_all元數(shù)據(jù)紊册,在建立索引的時候比肄,每插入一條document,它里面包含了多個field囊陡,此時芳绩,es會自動將多個field的值,全部用字符串的方式串聯(lián)起來撞反,變成一個長的字符串妥色,作為_all field的值,同時建立索引遏片;
后面如果在搜索的時候嘹害,沒有對某個field指定搜索撮竿,就默認搜索_all field,其中是包含了所有field的值的笔呀。
舉個例子
{
"name": "tom",
"age": 25,
"email": "tom@1qq.com",
"address": "beijing"
}
tom 25 tom@qq.com beijing
幢踏,作為這一條document的_all field的值,同時進行分詞后建立對應的倒排索引许师;生產(chǎn)環(huán)境通常不使用
5.5 mapping到底是什么房蝉?
自動或手動為index中的type建立的一種數(shù)據(jù)結(jié)構(gòu)和相關(guān)配置,簡稱為mapping微渠。
當添加數(shù)據(jù)時會dynamic mapping搭幻,自動為我們建立index,創(chuàng)建type敛助,以及type對應的mapping粗卜,mapping中包含了每個field對應的數(shù)據(jù)類型,以及如何分詞等設置纳击。
示例
添加一些測試數(shù)據(jù)
PUT /website/_doc/1
{
"post_date": "2020-01-01",
"title": "my first article",
"content": "this is my first article in this website",
"author_id": 9527
}
PUT /website/_doc/2
{
"post_date": "2020-01-02",
"title": "my second article",
"content": "this is my second article in this website",
"author_id": 9527
}
PUT /website/_doc/3
{
"post_date": "2020-01-03",
"title": "my third article",
"content": "this is my third article in this website",
"author_id": 9527
}
嘗試如下搜索续扔,只會返回1條數(shù)據(jù):
GET /website/_search?q=2020
GET /website/_search?q=2020-01-02
GET /website/_search?q=post_date:2020-01-01
GET /website/_search?q=post_date:2020
查看mapping
GET /website/_mapping
搜索結(jié)果為什么不一致,因為es自動建立mapping的時候焕数,設置了不同的field不同的data type纱昧。不同的data type的分詞、搜索等行為是不一樣的堡赔。所以出現(xiàn)了_all field和post_date field的搜索表現(xiàn)不是我們所期望的
5.6 精確匹配與全文搜索的對比分析
精確匹配(exact value)
2020-01-01识脆,exact value,搜索的時候善已,2020-01-01灼捂,才能搜索出來;如果你輸入一個01换团,是搜索不出來的
全文搜索(full text)
- 縮寫 vs. 全程:cn vs. china悉稠;如2020-01-01,2020 01 01艘包,搜索2020的猛,或者01,都可以搜索出來想虎;china卦尊,搜索cn,也可以將china搜索出來
- 格式轉(zhuǎn)化:like liked likes舌厨;likes岂却,搜索like,也可以將likes搜索出來
- 大小寫:Tom vs tom;Tom淌友,搜索tom煌恢,也可以將Tom搜索出來
- 同義詞:like vs love骇陈;like震庭,搜索love,同義詞你雌,也可以將like搜索出來
所有全文搜索不只是匹配完整的一個值器联,而是可以對值進行拆分詞語后(分詞)進行匹配,也可以通過縮寫婿崭、時態(tài)拨拓、大小寫、同義詞等進行匹配氓栈。
5.7 倒排索引核心原理
倒排索引(Inverted Index)也叫反向索引渣磷,有反向索引必有正向索引。通俗地來講授瘦,正向索引是通過key找value醋界,反向索引則是通過value找key。
doc1:I really liked my small dogs, and I think my mom also liked them.
doc2:He never liked any dogs, so I hope that my mom will not expect me to liked him.
分詞提完,初步的倒排索引的建立
|word |doc1|doc2|
|: |: |: |
|I | * | * |
|really| * | |
|liked | * | |
|my | * | * |
|small | * | |
|dogs | * | |
|and | * | |
....
搜索mother like little dog
形纺,不可能有任何結(jié)果
這個是不是我們想要的搜索結(jié)果,因為在我們看來徒欣,mother和mom有區(qū)別嗎逐样?同義詞,都是媽媽的意思打肝。like和liked有區(qū)別嗎脂新?沒有,都是喜歡的意思粗梭,只不過一個是現(xiàn)在時争便,一個是過去時。little和small有區(qū)別嗎楼吃?同義詞始花,都是小小的。dog和dogs有區(qū)別嗎孩锡?狗酷宵,只不過一個是單數(shù),一個是復數(shù)躬窜。
因此正常情況下在建立倒排索引的時候浇垦,會執(zhí)行一個normalization操作,對拆分出的各個單詞進行相應的處理荣挨,以提升后面搜索的時候能夠搜索到相關(guān)聯(lián)的文檔的概率
重新建立倒排索引男韧,加入normalization朴摊,再次用mother liked little dog搜索,就可以搜索到了
mother like little dog
會先分詞再normalization(時態(tài)的轉(zhuǎn)換此虑,單復數(shù)的轉(zhuǎn)換甚纲,同義詞的轉(zhuǎn)換,大小寫的轉(zhuǎn)換)
mother --> mom
like --> like
little --> little
dog --> dog
doc1和doc2都會搜索出來
5.8 分詞器的內(nèi)部組成到底是什么朦前,以及內(nèi)置分詞器的介紹
什么是分詞器
一個分詞器介杆,將一段文本拆分成一個一個的單個的單詞,同時對每個單詞進行normalization(時態(tài)轉(zhuǎn)換韭寸,單復數(shù)轉(zhuǎn)換)春哨,最后將處理好的結(jié)果才會拿去建立倒排索引。
切分詞語恩伺,normalization(提升召回率【recall】)赴背;具體包含如下:
recall,召回率:搜索的時候晶渠,增加能夠搜索到的結(jié)果的數(shù)量
character filter:在一段文本進行分詞之前凰荚,先進行預處理,比如說最常見的就是乱陡,過濾html標簽(<span>hello<span> --> hello)浇揩,& --> and(I&you --> I and you)
tokenizer:分詞憨颠,hello you and me --> hello, you, and, me
token filter:lowercase,stop word养盗,synonymom,dogs --> dog往核,liked --> like嚷节,Tom --> tom聂儒,a/the/an --> 干掉衩婚,mother --> mom非春,small --> little
5.9 query string的分詞以及mapping
query string必須以和index建立時相同的analyzer進行分詞
query string對exact value和full text的區(qū)別對待
不同類型的field,可能有的就是full text护侮,有的就是exact value羊初;因此上面進行搜索時查詢結(jié)果不是我們預期的
測試分詞器
GET /_analyze
{
"analyzer": "standard",
"text": "Text to analyze"
}
5.10 什么是mapping再次回爐透徹理解
- 往es里面直接插入數(shù)據(jù)业踏,es會自動建立索引勤家,同時建立type以及對應的mapping
- mapping中就自動定義了每個field的數(shù)據(jù)類型
- 不同的數(shù)據(jù)類型(比如說text和date)伐脖,可能有的是exact value,有的是full text
- exact value绎巨,在建立倒排索引的時候场勤,分詞的時候歼跟,是將整個值一起作為一個關(guān)鍵詞建立到倒排索引中的哈街;full text骚秦,會經(jīng)歷各種各樣的處理作箍,分詞蒙揣,normaliztion(時態(tài)轉(zhuǎn)換,同義詞轉(zhuǎn)換嗤详,大小寫轉(zhuǎn)換),才會建立到倒排索引中
- 同時呢苍狰,exact value和full text類型的field就決定了淋昭,在一個搜索過來的時候翔忽,對exact value field或者是full text field進行搜索的行為也是不一樣的,會跟建立倒排索引的行為保持一致材失;比如說exact value搜索的時候龙巨,就是直接按照整個值進行匹配恭应,full text query string,也會進行分詞和normalization再去倒排索引中去搜索
- 可以用es的dynamic mapping胆屿,讓其自動建立mapping非迹,包括自動設置數(shù)據(jù)類型冷离;也可以提前手動創(chuàng)建index和type的mapping需曾,自己對各個field進行設置杆兵,包括數(shù)據(jù)類型,包括索引行為旧找,包括分詞器钦讳,等等
mapping缚去,就是index的type的元數(shù)據(jù)易结,每個type都有一個自己的mapping搞动,決定了數(shù)據(jù)類型矗烛,建立倒排索引的行為瞭吃,還有進行搜索的行為
5.11 mapping的核心數(shù)據(jù)類型以及dynamic mapping
核心的數(shù)據(jù)類型
string
byte,short和蚪,integer攒霹,long
float旅薄,double
boolean
date
dynamic mapping類型推測
true or false --> boolean
123 --> long
123.01 --> double
2020-01-01 --> date
"hello world es" --> string/text
5.12 手動建立和修改mapping以及定制string類型數(shù)據(jù)是否分詞
如何建立索引
analyzed ------ 分詞類型
not_analyzed ------ 不分詞
no ------ 不分詞同時不能被搜索
只能創(chuàng)建index時手動建立mapping少梁,或者新增field mapping,但是不能update field mapping
PUT /website
{
"mappings": {
"properties": {
"author_id": {
"type": "long"
},
"title": {
"type": "text",
"analyzer": "english"
},
"content": {
"type": "text"
},
"post_date": {
"type": "date"
},
"publisher_id": {
"type": "keyword"
},
"is_del": {
"type":"boolean",
"index":false
}
}
}
}
"index":false 表示不加入索引
"type": "keyword" 表示不分詞妨马,在7.x版本后not_analyzed已經(jīng)被取消掉了
新增filed mapping
PUT /website/_mapping
{
"properties":{
"new_filed":{
"type":"text",
"index":false
}
}
}
5.13 mapping復雜數(shù)據(jù)類型以及object類型數(shù)據(jù)底層結(jié)構(gòu)
multivalue field
{ "tags": [ "tag1", "tag2" ]}
建立索引時與string是一樣的,數(shù)據(jù)類型不能混
empty field
null滤淳,[],[null]
object field
PUT /company/employee/1
{
"address": {
"country": "china",
"province": "guangdong",
"city": "guangzhou"
},
"name": "jack",
"age": 27,
"join_date": "2020-01-01"
}
對應這種object類型的底層數(shù)據(jù)存儲示例
"authors": [
{ "age": 26, "name": "Jack White"},
{ "age": 55, "name": "Tom Jones"},
{ "age": 39, "name": "Kitty Smith"}
]
上面的會轉(zhuǎn)換成下面這種:
{
"authors.age": [26, 55, 39],
"authors.name": [jack, white, tom, jones, kitty, smith]
}
5.14 search api的基礎語法介紹
search api的基本語法
GET /search
{}
GET /index1,index2/type1,type2/search
{}
GET /_search
{
"from": 0,
"size": 10
}
http協(xié)議中g(shù)et是否可以帶上request body
HTTP協(xié)議屁擅,一般不允許get請求帶上request body,但是因為get更加適合描述查詢數(shù)據(jù)的操作硝皂。
碰巧,很多瀏覽器贝或,或者是服務器咪奖,也都支持GET+request body模式趟佃;如果遇到不支持的場景闲昭,也可以用POST /_search
5.15 快速上機動手實戰(zhàn)Query DSL搜索語法
示例什么是Query DSL
GET /_search
{
"query": {
"match_all": {}
}
}
Query DSL的基本語法
{
QUERY_NAME: {
ARGUMENT: VALUE,
ARGUMENT: VALUE,...
}
}
{
QUERY_NAME: {
FIELD_NAME: {
ARGUMENT: VALUE,
ARGUMENT: VALUE,...
}
}
}
示例
GET /test_index/_search
{
"query": {
"match": {
"test_field": "test"
}
}
}
如何組合多個搜索條件
初始數(shù)據(jù):
PUT /website/_doc/1
{
"title": "my elasticsearch article",
"content": "es is very bad",
"author_id": 110
}
PUT /website/_doc/2
{
"title": "my elasticsearch article",
"content": "es is very good",
"author_id": 111
}
PUT /website/_doc/3
{
"title": "my elasticsearch article",
"content": "es is just so so",
"author_id": 112
}
- title必須包含elasticsearch,content可以包含elasticsearch也可以不包含,author_id必須不為111
GET /website/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"title": "elasticsearch"
}
}
],
"should": [
{
"match": {
"content": "elasticsearch"
}
}
],
"must_not": [
{
"match": {
"author_id": 111
}
}
]
}
}
}
示例2
GET /website/_search
{
"query": {
"bool": {
"must": {
"match": {
"name": "tom"
}
},
"should": [
{
"match": {
"hired": true
}
},
{
"bool": {
"must": {
"match": {
"personality": "good"
}
},
"must_not": {
"match": {
"rude": true
}
}
}
}
],
"minimum_should_match": 1
}
}
}
should 相當于or
bool 相當于()
must 相當于and
must_not 就是不等于
5.16 filter與query深入對比解密:相關(guān)度租幕,性能
filter與query示例
PUT /company/_doc/1
{
"join_date": "2016-01-01",
"age":33,
"name":"tom cat"
}
PUT /company/_doc/2
{
"join_date": "2016-01-01",
"age":29,
"name":"jerry mouse"
}
搜索請求:年齡必須大于等于30,同時join_date必須是2016-01-01
GET /company/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"join_date": "2016-01-01"
}
}
],
"filter": {
"range": {
"age": {
"gte": 30
}
}
}
}
}
}
filter與query對比大解密
- filter蝎宇,僅僅只是按照搜索條件過濾出需要的數(shù)據(jù)而已姥芥,不計算任何相關(guān)度分數(shù)凉唐,對相關(guān)度沒有任何影響
- query淡溯,會去計算每個document相對于搜索條件的相關(guān)度咱娶,并按照相關(guān)度進行排序
一般來說屈糊,如果你是在進行搜索逻锐,需要將最匹配搜索條件的數(shù)據(jù)先返回,那么用query鳄哭;如果只是要根據(jù)一些條件篩選出一部分數(shù)據(jù),不關(guān)注其排序勺拣,那么用filter
除非是你的這些搜索條件,你希望越符合這些搜索條件的document越排在前面返回愤惰,那么這些搜索條件要放在query中宦言;如果你不希望一些搜索條件來影響你的document排序奠旺,那么就放在filter中即可
filter與query性能
- filter,不需要計算相關(guān)度分數(shù)忿晕,不需要按照相關(guān)度分數(shù)進行排序杏糙,同時還有內(nèi)置的自動cache最常使用filter的數(shù)據(jù)
- query宏侍,相反咱旱,要計算相關(guān)度分數(shù)吐限,按照分數(shù)進行排序,而且無法cache結(jié)果
bool狐粱,must,must_not蒋搜,should,filter
每個子查詢都會計算一個document針對它的相關(guān)度分數(shù)祷杈,然后bool綜合所有分數(shù)宿刮,合并為一個分數(shù)僵缺,當然filter是不會計算分數(shù)的
5.17 常用的各種query搜索語法
match all
GET /_search
{
"query": {
"match_all": {}
}
}
match
GET /_search
{
"query": { "match": { "title": "my elasticsearch article" }}
}
multi match
GET /test_index/_search
{
"query": {
"multi_match": {
"query": "test",
"fields": ["test_field", "test_field1"]
}
}
}
range query
GET /company/_search
{
"query": {
"range": {
"age": {
"gte": 30
}
}
}
}
term query
GET /test_index/_search
{
"query": {
"term": {
"test_field": "test hello"
}
}
}
terms query
對tag指定多個分組詞
GET /_search
{
"query": { "terms": { "tag": [ "search", "full_text", "nosql" ] }}
}
5.18 如何定位不合法的搜索以及其原因
GET /company/_validate/query?explain
{
"query": {
"match": {
"name": "cat"
}
}
}
一般用在那種特別復雜龐大的搜索下容贝,比如一下子寫了上百行的搜索斤富,這個時候可以先用validate api去驗證一下,搜索是否合法
5.19 如何定制搜索結(jié)果的排序規(guī)則
默認排序規(guī)則
默認情況下油额,是按照_score降序排序的;然而,某些情況下看峻,可能沒有有用的_score互妓,比如說filter
GET /_search
{
"query": {
"bool": {
"filter": {
"term": {
"name": "cat"
}
}
}
}
}
當然,也可以是constant_score
GET /_search
{
"query": {
"constant_score": {
"filter": {
"term": {
"author_id": 1
}
}
}
}
}
定制排序規(guī)則
使用sort來定制排序規(guī)則
GET /company/_search
{
"query": {
"constant_score": {
"filter": {
"range": {
"age": {
"gte": 25
}
}
}
}
},
"sort": [
{
"join_date": {
"order": "asc"
}
}
]
}
5.20 如何將一個field索引兩次來解決字符串排序問題
如果對一個string field進行排序,結(jié)果往往不準確,因為分詞后是多個單詞蝴簇,再排序就不是我們想要的結(jié)果了
通常解決方案是,將一個string field建立兩次索引互拾,一個分詞寄猩,用來進行搜索;一個不分詞斯辰,用來進行排序
示例:先創(chuàng)建索引
PUT /website
{
"mappings": {
"properties": {
"title": {
"type": "text",
"fields": {
"raw": {
"type": "keyword"
}
},
"fielddata": true
},
"content": {
"type": "text"
},
"post_date": {
"type": "date"
},
"author_id": {
"type": "long"
}
}
}
}
設置正排索引 "fielddata": true
添加初始數(shù)據(jù)
PUT /website/_doc/1
{
"title": "first article",
"content": "this is my first article",
"post_date": "2017-01-01",
"author_id": 110
}
PUT /website/_doc/2
{
"title": "second article",
"content": "this is my second article",
"post_date": "2018-01-01",
"author_id": 111
}
執(zhí)行查詢
GET /website/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"title.raw": {
"order": "desc"
}
}
]
}
5.21 相關(guān)度評分TF&IDF算法
TF&IDF算法介紹
- relevance score算法柄瑰,簡單來說蒲跨,就是計算出或悲,一個索引中的文本,與搜索文本男公,他們之間的關(guān)聯(lián)匹配程度;
- Elasticsearch使用的是 term frequency/inverse document frequency算法,簡稱為TF/IDF算法;
- Term frequency:搜索文本中的各個詞條在field文本中出現(xiàn)了多少次镀琉,出現(xiàn)次數(shù)越多屋摔,就越相關(guān);
- Inverse document frequency:搜索文本中的各個詞條在整個索引的所有文檔中出現(xiàn)了多少次替梨,出現(xiàn)的次數(shù)越多钓试,就越不相關(guān);
舉個例子:
搜索請求:hello world
doc1:hello, today is very good
doc2:hi world, how are you
比如說副瀑,在index中有1萬條document,hello這個單詞在所有的document中糠睡,一共出現(xiàn)了1000次挽鞠;world這個單詞在所有的document中,一共出現(xiàn)了100次狈孔;那么doc2的相關(guān)度越高
- Field-length norm:field內(nèi)容長度信认,越長,相關(guān)度越弱
5.22 內(nèi)核級知識點之doc value初步探秘
搜索的時候均抽,要依靠倒排索引嫁赏;排序的時候,需要依靠正排索引油挥,看到每個document的每個field潦蝇,然后進行排序,所謂的正排索引喘漏,其實就是doc values护蝶;
在建立索引的時候,一方面會建立倒排索引翩迈,以供搜索用持灰;一方面會建立正排索引,也就是doc values负饲,以供排序堤魁,聚合,過濾等操作使用返十;
doc values是被保存在磁盤上的妥泉,此時如果內(nèi)存足夠,os會自動將其緩存在內(nèi)存中洞坑,性能還是會很高盲链;如果內(nèi)存不足夠,os會將其寫入磁盤上;
倒排索引類似如下(對每個字段進行操作):
doc1的content字段內(nèi)容: hello world you and me
doc2的content字段內(nèi)容: hi, world, how are you
對上面的內(nèi)容進行分詞刽沾,拆分為一個個單詞(term)本慕,建立類似如下的字典目錄
term | Posting List(倒排列表) |
---|---|
world | [doc1,doc2] |
hello | doc1 |
hi | doc2 |
... | .... |
Posting List(倒排列表)里面是文檔的id
這樣在搜索時根據(jù)term的索引(類似MySQL的索引)去找到符合的term進而找到對應的文檔信息;
可以這樣理解倒排索引:通過單詞找到對應的倒排列表侧漓,根據(jù)倒排列表中的倒排項進而可以找到文檔記錄锅尘;過程類型如下圖:
正排索引類似如下(對整個文檔進行操作):
doc1內(nèi)容: { "name": "jack", "age": 27 }
doc2內(nèi)容: { "name": "tom", "age": 30 }
document name age
doc1 jack 27
doc2 tom 30
5.23 分布式搜索引擎內(nèi)核解密之query phase
query phase
- 搜索請求發(fā)送到某一個coordinate node,構(gòu)構(gòu)建一個priority queue布蔗,長度以paging操作from和size為準藤违,默認為10
- coordinate node將請求轉(zhuǎn)發(fā)到所有shard,每個shard本地搜索纵揍,并構(gòu)建一個本地的priority queue
- 各個shard將自己的priority queue返回給coordinate node顿乒,并構(gòu)建一個全局的priority queue
replica shard如何提升搜索吞吐量
一次請求要打到所有shard的一個replica/primary上去,如果每個shard都有多個replica骡男,那么同時并發(fā)過來的搜索請求可以同時打到其他的replica上去
5.24 分布式搜索引擎內(nèi)核解密之fetch phase
fetch phbase工作流程
- coordinate node構(gòu)建完priority queue之后淆游,就發(fā)送mget請求去所有shard上獲取對應的document
- 各個shard將document返回給coordinate node
- coordinate node將合并后的document結(jié)果返回給client客戶端
一般搜索,如果不加from和size隔盛,就默認搜索前10條犹菱,按照_score排序
5.25 搜索相關(guān)參數(shù)梳理以及bouncing results問題解決方案
preference
決定了哪些shard會被用來執(zhí)行搜索操作
_primary, _primary_first, _local, _only_node:xyz, _prefer_node:xyz, _shards:2,3
bouncing results問題,兩個document排序吮炕,field值相同腊脱;不同的shard上,可能排序不同龙亲;每次請求輪詢打到不同的replica shard上陕凹;每次頁面上看到的搜索結(jié)果的排序都不一樣。這就是bouncing result鳄炉,也就是跳躍的結(jié)果杜耙。
搜索的時候,是輪詢將搜索請求發(fā)送到每一個replica shard(primary shard)拂盯,但是在不同的shard上佑女,可能document的排序不同
解決方案就是將preference設置為一個字符串,比如說user_id谈竿,讓每個user每次搜索的時候团驱,都使用同一個replica shard去執(zhí)行,就不會看到bouncing results了
timeout
主要就是限定在一定時間內(nèi)空凸,將部分獲取到的數(shù)據(jù)直接返回嚎花,避免查詢耗時過長
routing
document文檔路由,_id路由呀洲,routing=user_id紊选,這樣的話可以讓同一個user對應的數(shù)據(jù)到一個shard上去
search_type
default:query_then_fetch
dfs_query_then_fetch啼止,可以提升revelance sort精準度
5.26 基于scoll技術(shù)滾動搜索大量數(shù)據(jù)
如果一次性要查出來10萬條數(shù)據(jù),那么性能會很差丛楚,此時一般會采取用scoll滾動查詢族壳,一批一批的查,直到所有數(shù)據(jù)都查詢完處理完趣些。
使用scoll滾動搜索,可以先搜索一批數(shù)據(jù)贰您,然后下次再搜索一批數(shù)據(jù)坏平,以此類推,直到搜索出全部的數(shù)據(jù)來
scoll搜索會在第一次搜索的時候锦亦,保存一個當時的視圖快照舶替,之后只會基于該舊的視圖快照提供數(shù)據(jù)搜索,如果這個期間數(shù)據(jù)變更杠园,是不會讓用戶看到的
采用基于_doc進行排序的方式顾瞪,性能較高
每次發(fā)送scroll請求,我們還需要指定一個scoll參數(shù)抛蚁,指定一個時間窗口陈醒,每次搜索請求只要在這個時間窗口內(nèi)能完成就可以了;
GET /website/_search?scroll=1m
{
"query": {
"match_all": {}
},
"sort": [ "_doc" ],
"size": 3
}
獲得的結(jié)果會有一個scoll_id瞧甩,下一次再發(fā)送scoll請求的時候钉跷,必須帶上這個scoll_id
GET /_search/scroll
{
"scroll": "1m",
"scroll_id" : "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFHg3bnJvM01CYXBadGRjZ1FELWNqAAAAAAAADY8WdXVKQzR3TzVSMEtialVYM1gxbWkzZw=="
}
六、索引管理
6.1 索引的創(chuàng)建肚逸、修改爷辙、刪除
創(chuàng)建索引
指定分片信息、mapping信息
PUT /index_demo
{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 0
},
"mappings": {
"properties": {
"name":{
"type": "text"
}
}
}
}
使用默認的配置
PUT /index_pretty?pretty
修改索引
PUT /index_demo/_settings
{
"number_of_replicas": 1
}
刪除索引
DELETE /index_demo
DELETE /index_1,index_2
DELETE /index_demo*
DELETE /_all
6.2 修改分詞器以及定制自己的分詞器
默認的分詞器standard
- standard tokenizer:以單詞邊界進行切分
- standard token filter:什么都不做
- lowercase token filter:將所有字母轉(zhuǎn)換為小寫
- stop token filer(默認被禁用):移除停用詞朦促,比如a the it等等
修改分詞器的設置
- 啟用english停用詞token filter(創(chuàng)建索引的時候才可以)
PUT /index_demo
{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 0,
"analysis": {
"analyzer": {
"es_std":{
"type": "standard",
"stopwords": "_english_"
}
}
}
},
"mappings": {
"properties": {
"name":{
"type": "text"
}
}
}
}
測試定制的分詞器的效果:
# 使用定制的
GET /index_demo/_analyze
{
"analyzer": "es_std",
"text": "a dog is in the house"
}
# 使用默認的
GET /index_demo/_analyze
{
"analyzer": "standard",
"text":"a dog is in the house"
}
定制分詞器
將&
轉(zhuǎn)換為and膝晾,a 、the
不做處理务冕,將html標簽過濾掉血当,將字符轉(zhuǎn)為小寫的
PUT /index_demo
{
"settings": {
"analysis": {
"char_filter": {
"&_to_and": {
"type": "mapping",
"mappings": ["&=> and"]
}
},
"filter": {
"my_stopwords":{
"type": "stop",
"stopwords": ["the", "a"]
}
},
"analyzer": {
"my_analyzer":{
"type":"custom",
"char_filter": ["html_strip", "&_to_and"],
"tokenizer":"standard",
"filter":["lowercase","my_stopwords"]
}
}
}
}
}
測試定制的分詞器
GET /index_demo/_analyze
{
"text": "tom&jerry are a friend in the house, <a>, HAHA!!",
"analyzer": "my_analyzer"
}
6.3 深入探秘type底層數(shù)據(jù)結(jié)構(gòu)
type,是一個index中用來區(qū)分類似的數(shù)據(jù)的洒疚,類似的數(shù)據(jù)歹颓,但是可能有不同的fields,而且有不同的屬性來控制索引建立油湖、分詞器巍扛;
field的value,在底層的lucene中建立索引的時候乏德,全部是opaque bytes類型撤奸,不區(qū)分類型的吠昭;
lucene是沒有type的概念的,在document中胧瓜,實際上將type作為一個document的field來存儲矢棚,即_type,es通過_type來進行type的過濾和篩選府喳;
一個index中的多個type蒲肋,實際上是放在一起存儲的,因此一個index下钝满,不能有多個type重名兜粘,因為那樣是無法處理的;
在es7中一個index只能有一個type弯蚜,默認為_doc孔轴,不推薦去自定義了。
舉例說明
設置的mappings如下:
{
"ecommerce": {
"mappings": {
"_type": {
"type": "string",
"index": "not_analyzed"
},
"name": {
"type": "string"
}
"price": {
"type": "double"
}
"service_period": {
"type": "string"
}
"eat_period": {
"type": "string"
}
}
}
}
假設有如下2條數(shù)據(jù)存入
{
"name": "geli kongtiao",
"price": 1999.0,
"service_period": "one year"
}
{
"name": "aozhou dalongxia",
"price": 199.0,
"eat_period": "one week"
}
在底層的存儲是這樣子的
{
"_type": "elactronic_goods",
"name": "geli kongtiao",
"price": 1999.0,
"service_period": "one year",
"eat_period": ""
}
{
"_type": "fresh_goods",
"name": "aozhou dalongxia",
"price": 199.0,
"service_period": "",
"eat_period": "one week"
}
如果存入數(shù)據(jù)沒有某個filed時碎捺,將會存入一個空值路鹰;假如說,將兩個type的field完全不同收厨,放在一個index下晋柱,那么就每條數(shù)據(jù)都至少有一半的field在底層的lucene中是空值,會有嚴重的性能問題帽氓;
因此在es7中一個index只能有一個type趣斤,默認為_doc,不推薦去自定義了黎休。
6.4 mapping root object剖析
root object
就是某個type對應的mapping json浓领,包括了properties,metadata(_id势腮,_source联贩,_type),settings(analyzer)捎拯,其他settings(比如include_in_all)
PUT /index_demo
{
"mappings": {
"properties": {
}
}
}
properties
type泪幌,index,analyzer
PUT /index_demo/_mapping
{
"properties": {
"title": {
"type": "text"
}
}
}
_source
優(yōu)點:
- 查詢的時候署照,直接可以拿到完整的document祸泪,不需要先拿document id,再發(fā)送一次請求拿document
- partial update基于_source實現(xiàn)
- reindex時建芙,直接基于_source實現(xiàn)没隘,不需要從數(shù)據(jù)庫(或者其他外部存儲)查詢數(shù)據(jù)再修改
- 可以基于_source定制返回field
- debug query更容易,因為可以直接看到_source
如果不需要上述好處禁荸,可以禁用_source右蒲;但是不建議這么做官方說明
PUT /index_demo
{
"mappings": {
"_source": {"enabled": false}
}
}
標識性metadata
_index阀湿,_type,_id
6.5 定制化自己的dynamic mapping
定制dynamic策略
true:遇到陌生字段瑰妄,就進行dynamic mapping
false:遇到陌生字段陷嘴,就忽略
strict:遇到陌生字段,就報錯
示例:
PUT /index_demo
{
"mappings": {
"dynamic":"strict",
"properties": {
"title":{
"type": "text"
},
"address":{
"type": "object",
"dynamic": true
}
}
}
}
測試數(shù)據(jù)添加是否可以成功
PUT /index_demo/_doc/1
{
"title":"this is firestone",
"content":"this is content",
"address":{
"province":"北京",
"city":"北京"
}
}
由于做了現(xiàn)在间坐,因此上面這個會添加失敗
PUT /index_demo/_doc/1
{
"title":"this is firestone",
"address":{
"province":"北京",
"city":"北京"
}
}
定制dynamic mapping策略
默認會按照一定格式識別date灾挨,比如yyyy-MM-dd。但是如果某個field先過來一個2017-01-01的值竹宋,就會被自動dynamic mapping成date涨醋,
后面如果再來一個"hello world"之類的值,就會報錯逝撬。可以手動關(guān)閉某個type的date_detection乓土,如果有需要宪潮,自己手動指定某個field為date類型。
PUT /index_demo/_mapping
{
"date_detection": false
}
定制自己的dynamic mapping template
PUT /index_demo
{
"mappings": {
"dynamic_templates": [
{
"en": {
"match": "*_en",
"match_mapping_type": "string",
"mapping": {
"type": "text",
"analyzer": "english"
}
}
}
]
}
}
測試
PUT index_demo/_doc/1
{
"title":"this is my first article"
}
PUT index_demo/_doc/2
{
"title_en":"this is my first article"
}
GET /index_demo/_search
{
"query":{
"match": {
"title": "is"
}
}
}
title沒有匹配到任何的dynamic模板趣苏,默認就是standard分詞器狡相,不會過濾停用詞,is會進入倒排索引食磕,用is來搜索是可以搜索到的尽棕;
title_en匹配到了dynamic模板,就是english分詞器彬伦,會過濾停用詞滔悉,is這種停用詞就會被過濾掉,用is來搜索就搜索不到了单绑;
6.6 基于scoll+bulk+索引別名實現(xiàn)零停機重建索引
重建索引
一個field的設置是不能被修改的回官,如果要修改一個Field,那么應該重新按照新的mapping搂橙,建立一個index歉提,然后將數(shù)據(jù)批量查詢出來,重新用bulk api寫入index中区转;
批量查詢的時候苔巨,建議采用scroll api,并且采用多線程并發(fā)的方式來reindex數(shù)據(jù)废离,每次scoll就查詢指定日期的一段數(shù)據(jù)侄泽,交給一個線程即可;
舉個例子:
(1)一開始厅缺,依靠dynamic mapping蔬顾,插入數(shù)據(jù)宴偿,但是不小心有些數(shù)據(jù)是2017-01-01這種日期格式的,所以title這種field被自動映射為了date類型诀豁,實際上它應該是string類型的窄刘。
PUT /index_demo/_doc/1
{
"title":"2020-01-01"
}
PUT /index_demo/_doc/2
{
"title":"2020-01-02"
}
(2)當后期向索引中加入string類型的title值的時候,就會報錯舷胜。
PUT /index_demo/_doc/3
{
"title":"es 入門"
}
(3)如果此時想修改title的類型娩践,是不可能的
PUT /index_demo/_mapping
{
"properties":{
"title":{
"type":"text"
}
}
}
(4)此時,唯一的辦法烹骨,就是進行reindex翻伺,也就是說,重新建立一個索引沮焕,將舊索引的數(shù)據(jù)查詢出來吨岭,再導入新索引
(5)如果舊索引的名字是old_index,新索引的名字是new_index峦树,終端java應用辣辫,已經(jīng)在使用old_index在操作了,難道還要去停止java應用魁巩,修改使用的index為new_index急灭,才重新啟動java應用嗎?這個過程中谷遂,就會導致java應用停機葬馋,可用性降低
(6)所以說,給java應用一個別名肾扰,這個別名是指向舊索引的畴嘶,java應用先用著,java應用先用goods_index alias來操作白对,此時實際指向的是舊的my_index
PUT /index_demo/_alias/goods_index
(7)新建一個index掠廓,調(diào)整其title的類型為string
PUT /index_demo_new
{
"mappings": {
"properties": {
"title":{
"type":"text"
}
}
}
}
(8)使用scroll api將數(shù)據(jù)批量查詢出來
GET /index_demo/_search?scroll=1m
{
"query": {
"match_all": {}
},
"sort": ["_doc"],
"size": 1
}
(9)采用bulk api將scoll查出來的一批數(shù)據(jù),批量寫入新索引
POST /_bulk
{"index":{"_index":"index_demo_new", "_id":"1"}}
{"title":"2020-01-01"}
(10)反復循環(huán)8~9甩恼,查詢一批又一批的數(shù)據(jù)出來蟀瞧,采取bulk api將每一批數(shù)據(jù)批量寫入新索引
(11)將goods_index alias切換到my_index_new上去,java應用會直接通過index別名使用新的索引中的數(shù)據(jù)条摸,java應用程序不需要停機悦污,零提交,高可用
POST /_aliases
{
"actions": [
{
"remove": {
"index": "index_demo",
"alias": "goods_index"
}
},
{
"add": {
"index": "index_demo_new",
"alias": "goods_index"
}
}
]
}
(12)直接通過goods_index別名來查詢钉蒲,是否ok