安裝Elasticsearch
可以在https://www.elastic.co/cn/downloads/elasticsearch這個(gè)頁面找到elasticsearch對(duì)應(yīng)系統(tǒng)的安裝包,elasticsearch用java開發(fā)的, 最新的版本內(nèi)置了對(duì)應(yīng)的jdk, 通過下面的方式能快速啟動(dòng):
cd /安裝目錄/elasticsearch/bin
./elasticsearch
#驗(yàn)證是否啟動(dòng), 可以訪問: http://127.0.0.1:9200/
- 對(duì)于插件的安裝, 可以用bin目錄下的./elasticsearch-plugin 腳本, 比如安裝 ik分詞器:
./elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.8.0/elasticsearch-analysis-ik-7.8.0.zip
系統(tǒng)會(huì)下載需要安裝的插件, 然后解壓到plugins目錄下。也可以吧plugin直接下載到系統(tǒng), 解壓到plugin目錄。
安裝可視化工具Kibana
可以在https://www.elastic.co/cn/downloads/kibana這個(gè)頁面找到kibana對(duì)應(yīng)系統(tǒng)的安裝包,kibana用node開發(fā), 最新的版本內(nèi)置了對(duì)應(yīng)的node啟動(dòng)程序,啟動(dòng)流程如下:
- 解壓后修改config/kibana.yml里的配置, 需要設(shè)置 elasticsearch.hosts, 本地就是: http://127.0.0.1:9200/
- 如果想用中文環(huán)境, 可以修改config/kibana.yml文件, 設(shè)置i18n.locale: "zh-CN"
- 在/bin 目錄下啟動(dòng)kibana
文章后面的代碼都是在kibana 的Dev Tools 里操作完成
重要的概念
- 索引(Index): 這里的索引跟我們平時(shí)用Mysql里索引是不一樣的,在ES中, Index可以理解成Mysql里的一張表。ES通過不同的Index來管理數(shù)據(jù)
- 文檔(Document): 相當(dāng)于Mysql里的一行記錄, ES 里的數(shù)據(jù)是通過文檔來記錄的。
- 倒排索引: 把數(shù)據(jù)里的每個(gè)詞或者詞組(這里跟具體的分詞器相關(guān))映射到文檔的id。
- 節(jié)點(diǎn): 一個(gè)Elasticsearch 進(jìn)程。
- 集群: 多個(gè)節(jié)點(diǎn)組成的系統(tǒng)稱為集群。
- 分片: 邏輯的概念, 可以理解成對(duì)表做分庫分表
- 副本:某個(gè)分片的復(fù)制
- 類型: 文檔里字段的定義
- mappings: 對(duì)Index的描述, 類似于mysql里的Schemas
- type類型: ES對(duì)這個(gè)概念已經(jīng)廢棄, 不需要了解
數(shù)據(jù)類型
分類 | 具體類型 |
---|---|
字符串 | text: 會(huì)被分詞,能根據(jù)詞項(xiàng)快速檢索,比如文章的標(biāo)題,文本 。keyword: 不會(huì)被分詞,只能通過精確查詢,比如文章的作者 |
整型 | byte, short , int, long |
浮點(diǎn)型 | float, double, half_float (16位) , scaled_float(縮放類型,比如價(jià)格55.55, 存的是5555, 縮放因子為100) |
boolean | 值為true, false |
date | 日期類型 |
二進(jìn)制類型 | binary: 用的比較少,沒法做索引 |
array | 數(shù)組類型,數(shù)據(jù)里的類型可以是對(duì)象 |
object | 對(duì)象類型,文檔會(huì)包含嵌套的對(duì)象 |
nested | 嵌套類型, 他能夠保證數(shù)據(jù)之間的層級(jí)結(jié)構(gòu) |
索引的基本操作
- 創(chuàng)建索引, 類似操作mysql的建表語句, 這里初了需要關(guān)注各個(gè)字段的含義以外, 還需要關(guān)注settings里的分片數(shù)(number_of_shards)和副本數(shù)(number_of_replicas)。
PUT film
{
"mappings": {
"properties": {
"id":{
"type": "keyword",
"store":true
},
"name":{
"type": "keyword",
"store":true
},
"desc":{
"type":"text",
"store":true,
"analyzer": "ik_max_word"
},
"tag":{
"type": "keyword",
"store":true
},
"actors":{
"type": "nested",
"properties":{
"id":{
"type": "keyword",
"store":true
},
"name":{
"type": "keyword",
"store":true
},
"sex":{
"type": "integer",
"store":true
}
}
}
}
},
"settings": {
"number_of_replicas": 1,
"number_of_shards": 1
}
}
- 查看索引的元數(shù)據(jù)信息
GET film #film 是Index的名稱
- 刪除索引
DELETE film #film 是Index的名稱
對(duì)于索引沒有所謂的更新操作,如果對(duì)于有些字段的類型需要做更新,只能刪除原來的索引,重新創(chuàng)建新的索引。在實(shí)際的使用過程中,我們可以插入一些示例數(shù)據(jù),通過ES幫我們生成默認(rèn)mappings, 然后再對(duì)mappings做修改對(duì)于指定好的分片數(shù), 也是沒有辦法修改的, 如果想增加分片數(shù), 只能做reindex操作。
文檔的基本操作
- 新增文檔, 新增的時(shí)候需要指定id, 如果沒指定, ES會(huì)生成一個(gè)String類型的id
PUT /film/_doc/001
{
"id":"001",
"name":"甄嬛傳",
"desc":"雍正元年,結(jié)束了血腥的奪位之爭,新的君主(陳建斌 飾)繼位,國泰民安,政治清明,但在一片祥和的表象之下,一股暗流蠢蠢欲動(dòng),尤其后宮,華妃(蔣欣 飾)與皇后(蔡少芬 飾)分庭抗禮,各方勢力裹挾其中,兇險(xiǎn)異常。十七歲的甄嬛(孫儷飾)與好姐妹眉莊(斕曦飾)、陵容(陶昕然飾)參加選秀,她本抱著來充個(gè)數(shù)的念頭,可皇帝(陳建斌飾)偏相中了她的智慧、氣節(jié)與端莊,最后三人一同入選。但因華妃(蔣欣飾)囂張,步步緊逼,眉莊被冤,陵容變心,天真的甄嬛慢慢變成了后宮精明的女子。皇帝發(fā)現(xiàn)年羹堯(孫寧飾)的野心,令甄父剪除年氏一族,甄嬛終于斗倒了華妃。但由于甄嬛與先故純?cè)屎蟮纳袼疲屎笤O(shè)計(jì)以純?cè)屎蟮亩Y服陷害甄嬛,父親(沈保平飾)也被文字獄牽連和奸人陷害而遭牢獄之災(zāi),生下女兒后,心灰意冷的甄嬛選擇出宮修行。在宮外幸得十七爺允禮(李東學(xué)飾)悉心照顧,二人相親相愛,只等有機(jī)會(huì)遠(yuǎn)走高飛。后因誤傳十七爺死訊,甄嬛為保全腹中骨肉,設(shè)計(jì)與皇帝相遇,狠心斷絕對(duì)十七爺?shù)膼蹜伲鼗貙m中,再度與皇后相斗。后因生下雙生子,同時(shí)甄父的冤案得以平反,重新被皇帝重用,甄氏一族再度崛起。甄嬛多次躲過皇后的陷害,最終扳倒皇后。可造化弄人,由于皇帝的疑心,最終卻只能看著心上人允禮死在自己懷中,而與葉瀾依(熱依扎飾)合謀弒君。皇帝駕崩后,甄嬛養(yǎng)子弘歷登基,甄嬛被尊為圣母皇太后,即便享盡榮華,但眼見一生姐妹沈眉莊血崩而亡,一生愛人允禮為保其周全而無憾自盡,不過是一代封建王朝的悲情故夢罷了。",
"tag":["后宮","古裝","清朝","愛情","宮斗"],
"actors":[
{
"id":"actor_001",
"name":"孫儷",
"sex":0
},
{
"id":"actor_002",
"name":"陳建斌",
"sex":1
},
{
"id":"actor_003",
"name":"蔡少芬",
"sex":0
},
{
"id":"actor_004",
"name":"蔣欣",
"sex":0
},
{
"id":"actor_005",
"name":"藍(lán)盈盈",
"sex":0
}
]
}
- 修改文檔,修改文檔的時(shí)候,需要指定文檔的id, 并且在url后面加上_update表示更新, 其中的"doc" 表示修改文檔的內(nèi)容, 不加上會(huì)報(bào)錯(cuò)
POST /film/_update/001
{
"doc":{
"id":"001",
"tag":["后宮","古裝","清朝","愛情","宮斗","玄幻"],
"actors":[
{
"id":"actor_002",
"name":"陳建斌",
"sex":1
},
{
"id":"actor_006",
"name":"藍(lán)盈盈",
"sex":0
}
]
}
}
- 刪除文檔
DELETE /film/_doc/001
文檔查詢
對(duì)于查詢, 如果需要了解內(nèi)部是如何解析的, 可以在查詢里加上"profile": "true"。
- 最簡單的, 根據(jù)文檔Id查詢
GET /film/_doc/001 #001表示文檔的id
- 查看es分詞器的結(jié)果
GET _analyze
{
"analyzer": "ik_max_word", #分詞器
"text": "我是中國人"
}
- term查詢: 完全匹配,不會(huì)將指定的查詢關(guān)鍵字進(jìn)行分詞,直接去分詞庫中匹配,找到相應(yīng)的文檔內(nèi)容,類似于mysql里的“=”。
GET /film/_search
{
"query": {
"term": {
"name.keyword": { #這里需要指定對(duì)name的keyword查詢
"value": "甄嬛傳"
}
}
}
}
- terms查詢, 查詢機(jī)制更term一樣,類似于mysql里的in(?,?)
GET /film/_search
{
"profile": "true",
"query": {
"terms": {
"name": ["甄", "畫"]
}
}
}
- match_all查詢: 查詢?nèi)績?nèi)容,不指定任何查詢條件, 可以通過from, size 做分頁查詢
GET /film/_search
{
"from": 0,
"size": 2,
"query": {
"match_all": {}
}
}
- match查詢:match查詢屬于高級(jí)查詢,會(huì)根據(jù)你查詢的字段的類型不一致,采用不同的查詢方式。
- 如果查詢的是日期或者數(shù)值的字段,他會(huì)自動(dòng)將你的字符串查詢內(nèi)容轉(zhuǎn)換成日期或者數(shù)值對(duì)待;
- 如果查詢的內(nèi)容是一個(gè)不能被分詞的字段(keyword).match查詢不會(huì)對(duì)你的指定查詢關(guān)鍵字進(jìn)行分詞;
- 如果查詢的內(nèi)容是一個(gè)可以分詞的字段(text),match會(huì)將你指定的查詢內(nèi)容根據(jù)一定的方式去分詞,然后去分詞庫中匹配指定的內(nèi)容。
總而言之:match查詢,實(shí)際底層就是多個(gè)term查詢,將多個(gè)term查詢的結(jié)果匯集到一起返回給你。
GET /film/_search
{
"profile": "true",
"query": {
"match": {
"name": "甄"
}
}
}
- match_phrase查詢:首先解析查詢字符串來產(chǎn)生一個(gè)詞條列表(這里會(huì)分詞)。然后會(huì)搜索所有的詞條,只保留包含了所有搜索詞條的文檔,并且詞條的位置要鄰接可以通過slop來指定詞之間相隔多遠(yuǎn)還能匹配, 如果超過這個(gè)值, 文檔將匹配不上
GET /film/_search
{
"profile": "true",
"query": {
"match_phrase": {
"desc": {
"query": "國泰民安 祥和",
"slop": 8
}
}
}
}
- multi_match查詢:多字段進(jìn)行匹配, 只要有一個(gè)字段滿足搜索條件, 就能查詢出來, 對(duì)于多字段匹配的問題, 涉及到評(píng)分, 可以通過type來指定評(píng)分標(biāo)準(zhǔn),有三種類型,分別是: best_fields: 完全匹配的文檔占比高, 可以通過tie_breaker指定評(píng)分的系數(shù);most_fields:表示 越多字段匹配的文檔評(píng)分越;
cross_fields: 表示詞條的分詞詞匯是分配到不同字段中評(píng)分高。
GET /film/_search
{
"profile": "true",
"query": {
"multi_match": {
"query": "傳",
"fields": ["name", "desc", "tag"]
}
}
}
GET /film/_search
{
"profile": "true",
"query": {
"multi_match": {
"query": "民國",
"fields": ["name", "desc", "tag"],
"type": "best_fields",
"tie_breaker": 0.5
}
}
}
- bool聯(lián)合查詢: 其中 must: 表示文檔必須完全匹配, must_not: 表示文檔必須不能匹配,should表示下面的條件只要有一個(gè)滿足, 就能查出來, 類似sql的or
GET /film/_search
{
"profile": "true",
"query": {
"bool": {
"must": [
{
"term": {
"tag.keyword": {
"value": "愛情"
}
}
}
],
"must_not": [
{"term": {
"tag.keyword": {
"value": "土匪"
}
}}
]
}
}
}
- 范圍查詢:類似于sql里的between and
GET /sms-logs-index/_search
{
"profile": "true",
"query": {
"range": {
"fee": {
"gte": 50,
"lte": 500
}
}
}
}
GET /sms-logs-index/_search
{
"profile": "true",
"query": {
"range": {
"createDate": {
"gte": "2020-09-16",
"lte": "2020-09-21"
}
}
}
}
- 對(duì)于nested類型的查詢, 需要指定path
GET /film/_search
{
"query": {
"bool": {
"must": [
{
"nested": {
"path": "actors", #這里需要指定查詢的path
"query": {
"bool": {
"must": [{
"term": {
"actors.name": "周迅"
}
}]
}
}
}
},
{
"term":{"tag":"民國"}
}
]
}
}
}
- 通過sort對(duì)數(shù)據(jù)做排序
GET /sms-logs-index/_search
{
"profile": "true",
"from": 0,
"size": 2,
"query": {
"range": {
"fee": {
"gte": 50,
"lte": 500
}
}
},
"sort": [
{
"fee": {
"order": "desc"
}
}
]
}
分頁
- 通過from + size 淺分頁, 這種分頁方式默認(rèn)值能查詢10000條數(shù)據(jù)
- scroll 方式獲取深分頁的數(shù)據(jù), 查詢的時(shí)候URL上需要有scroll參數(shù)表示這個(gè)scroll存在的時(shí)間,比如5m表示存在5分鐘。之后的請(qǐng)求的接口不再使用索引名了,而是 _search/scroll,GET和POST方法都可以使用, 需要重新設(shè)置scroll存在的時(shí)間。 在查詢的時(shí)候, 不能加上"profile": "true", 不然后面的查詢會(huì)報(bào)錯(cuò):The collector can only be set once 問題的鏈接在這里:https://github.com/elastic/elasticsearch/issues/27376。scroll 方式獲取數(shù)據(jù)會(huì)生成歷史快照,對(duì)于數(shù)據(jù)的變更不會(huì)反映到快照上。
GET /sms-logs-index/_search?scroll=5m
{
"from": 0,
"size": 2,
"query": {
"range": {
"fee": {
"gte": 50,
"lte": 500
}
}
}
}
GET /_search/scroll
{
"scroll": "5m",
"scroll_id": "FGluY2x1ZGVfY29udGV4dF91dWlkDnF1ZXJ5VGhlbkZldGNoBRRwVTRQUm5ZQllORnB0eHdqcVRpMgAAAAAAAAB-FlAxRDB2cU96UzdhbWRQSXAyWWZnZUEUcGs0UFJuWUJZTkZwdHh3anFUaTIAAAAAAAAAfxZQMUQwdnFPelM3YW1kUElwMllmZ2VBFHAwNFBSbllCWU5GcHR4d2pxVGkyAAAAAAAAAIAWUDFEMHZxT3pTN2FtZFBJcDJZZmdlQRRxRTRQUm5ZQllORnB0eHdqcVRpMgAAAAAAAACBFlAxRDB2cU96UzdhbWRQSXAyWWZnZUEUcVU0UFJuWUJZTkZwdHh3anFUaTMAAAAAAAAAghZQMUQwdnFPelM3YW1kUElwMllmZ2VB"
}
- search_after 深分頁; 分頁的方式是根據(jù)上一頁的最后一條數(shù)據(jù)來確定下一頁的位置, 在查詢的時(shí)候需要有sort, 并且排序的字段組合能有唯一性不然中間查詢的時(shí)候會(huì)有數(shù)據(jù)丟失, from一定是從零開始。
GET /sms-logs-index/_search
{
"profile": "true",
"from": 0,
"size": 2,
"query": {
"range": {
"fee": {
"gte": 50,
"lte": 500
}
}
},
"sort": [
{
"fee": {
"order": "desc"
},
"longCode":{
"order": "desc"
}
}
]
}
GET /sms-logs-index/_search
{
"profile": "true",
"from": 0,
"size": 2,
"query": {
"range": {
"fee": {
"gte": 50,
"lte": 500
}
}
},
"search_after":[200, 87454120],
"sort": [
{
"fee": {
"order": "desc"
},
"longCode":{
"order": "desc"
}
}
]
}
聚合查詢
聚合查詢一般用于對(duì)數(shù)據(jù)做統(tǒng)計(jì), 比如每個(gè)城市雙11消費(fèi)了多少, 用戶使用系統(tǒng)的平均時(shí)間是多少。聚合查詢分下面幾類
指標(biāo)聚合
- 對(duì)文檔的特定字段(field)或腳本值(generated using scripts),計(jì)算最大值(max), 最小值(min), 平均值(avg), 求和(sum)。
GET /sms-logs-index/_search
{
"profile": "true",
"aggs": {
"fee_max": { #聚合的名字
"max": { #聚合的類型
"field": "fee"
}
},
"fee_min":{
"min": {
"field": "fee"
}
},
"fee_sum":{
"sum": {
"field": "fee"
}
}
,
"fee_avg":{
"avg": {
"field": "fee"
}
}
}
}
- distinct 聚合(cardinality),統(tǒng)計(jì)某個(gè)字段有多少種值
GET /sms-logs-index/_search
{
"profile": "true",
"aggs": {
"fee_count": {
"cardinality": {
"field": "fee"
}
}
}
}
- 統(tǒng)計(jì)聚合(stats),統(tǒng)計(jì)的值包含 sum, avg , min, max , count
GET /sms-logs-index/_search
{
"profile": "true",
"aggs": {
"fee_stat": {
"stats": {
"field": "fee"
}
}
}
}
- 百分比統(tǒng)計(jì)
GET /sms-logs-index/_search
{
"profile": "true",
"size": 1,
"aggs": {
"fee_percents": {
"percentiles": {
"field": "fee",
"percents": [ #需要統(tǒng)計(jì)的百分比
1,
10,
25,
50,
75,
95,
99
]
}
}
}
}
- 百分比排名聚合, 用于統(tǒng)計(jì)類似于: 小費(fèi)在 200一下的占的百分比是多少。
GET /sms-logs-index/_search
{
"profile": "true",
"size": 1,
"aggs": {
"fee_percents": {
"percentile_ranks": {
"field": "fee",
"values": [200, 2000]
}
}
}
}
桶聚合
對(duì)文檔進(jìn)行分組的操作(與sql中的group by類似),把滿足相關(guān)特性的文檔分到一個(gè)桶里,即桶分,輸出結(jié)果往往是一個(gè)個(gè)包含多個(gè)文檔的桶(一個(gè)桶就是一個(gè)group)。
- Terms Aggregation 詞聚合
GET /sms-logs-index/_search
{
"profile": "true",
"size": 0,
"query": {
"term": {
"province": {
"value": "杭州"
}
}
},
"aggs": {
"province_terms": {
"terms": {
"field": "province",
"size": 10,
"min_doc_count": 4 #只返回文檔個(gè)數(shù)不小于該值的 buckets
}
}
}
}
- rang 范圍聚合
GET /sms-logs-index/_search
{
"profile": "true",
"size": 0,
"query": {
"term": {
"province": {
"value": "杭州"
}
}
},
"aggs": {
"fee_range": {
"range": {
"field": "fee",
"ranges": [
{
"from": 0,
"to": 100
},
{
"from": 100,
"to": 2000
}
]
}
}
}
}
- date_range 時(shí)間范圍查詢
GET /sms-logs-index/_search
{
"size": 0,
"aggs": {
"createDate_range": {
"date_range": {
"field": "createDate",
"ranges": [
{
"from": "2020-09-16",
"to": "2020-09-20"
},
{
"from": "2020-09-21",
"to": "2020-09-23"
}
]
}
}
}
}