ElasticSearch 進階
- 2021 年 3 月 9 日
- 筆記
- elasticsearch
ElasticSearch 進階
SearchAPI
ES 支援兩種基本方式檢索 :
- 一個是通過使用 REST request URI 發送搜索參數(uri+檢索參數)
- 一個是通過使用 REST request body 來發送它們(uri+請求體)
檢索資訊
請求參數 | 詳情 | |
---|---|---|
GET bank/_search | 檢索 bank 下所有資訊,包括 type 和 docs | |
GET bank/_search?q=*&sort=account_number:asc | 請求參數方式檢索 |
響應結果解釋:
took - Elasticsearch 執行搜索的時間(毫秒)
time_out - 告訴我們搜索是否超時
_shards - 告訴我們多少個分片被搜索了,以及統計了成功/失敗的搜索分片
hits - 搜索結果
hits.total - 搜索結果
hits.hits - 實際的搜索結果數組(默認為前 10 的文檔)
sort - 結果的排序 key(鍵)(沒有則按 score 排序)
score 和 max_score –相關性得分和最高得分(全文檢索用)
- uri+請求體
# GET查詢 kibana查詢
GET bank/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"account_number": "asc"
},
{
"balance": "desc"
}
]
}
HTTP 客戶端工具(POSTMAN),get 請求不能攜帶請求體,我們變為 post 也是一樣的我們 POST 一個 JSON 風格的查詢請求體到 _search API。
需要了解,一旦搜索的結果被返回,Elasticsearch 就完成了這次請求,並且不會維護任何
服務端的資源或者結果的 cursor(游標)
Query DSL
基本語法格式
Elasticsearch 提供了一個可以執行查詢的 Json 風格的 DSL(domain-specific language 領域特定語言)。這個被稱為Query DSL。該查詢語言非常全面,並且剛開始的時候感覺有點複雜, 學好它的方法是從一些基礎的示例開始的。
# 查詢語句
{
QUERY_NAME: {
ARGUMENT: VALUE,
ARGUMENT: VALUE,
...
}
}
# 查詢語句-針對某個欄位
{
QUERY_NAME: {
FIELD_NAME: {
ARGUMENT: VALUE,
ARGUMENT: VALUE,
...
}
}
}
查詢-match
# kibana查詢
GET bank/_search
{
"query": {
"match_all": {}
},
"from": 0,
"size": 5,
"sort": [
{
"account_number": {
"order": "desc"
}
}
]
}
query :定義查詢
match_all 查詢類型: 代表查詢所有的所有
from+size 限定: 分頁功能
sort : 排序
# kibana查詢-返回部分欄位
GET bank/_search
{
"query": {
"match_all": {}
},
"from": 0,
"size": 5,
"_source": ["age","balance"]
}
# kibana查詢-match查詢
基本類型(非字元串),精確匹配;match 返回 account_number=20 的數據
GET bank/_search
{
"query": {
"match": {
"account_number": "20"
}
}
}
# kibana查詢-字元串查詢
最終查詢出 address 中包含 mill 單詞的所有記錄
GET bank/_search
{
"query": {
"match": {
"address": "mill"
}
}
}
注: match 當搜索字元串類型的時候,會進行全文檢索,並且每條記錄有相關性得分。
# 字元串,多個單詞(分詞+全文檢索)
查詢-match_phrase
不分詞匹配
# 查出 address 中包含 mill road 的所有記錄,並給出相關性得分
GET bank/_search
{
"query": {
"match_phrase": {
"address": "mill road"
}
}
}
查詢-multi_match
多欄位匹配
# state 或 address 包含 mill 或 movico
GET bank/_search
{
"query": {
"multi_match": {
"query": "mill Movico",
"fields": ["state","address"]
}
}
}
查詢-bool複合查詢
bool 用來做複合查詢:
複合語句可以合併任何它查詢語句,包括複合語句,了解這一點是很重要的。
複合語句之間可以互相嵌套,可以表達非常複雜的邏輯。
# 查詢address必須為mill age必須為28 lastname可為helloand也可不為helloand的數據
# must:必須達到 must 列舉的所有條件
# must_not 必須不是指定的情況
# should:應該達到 should 列舉的條件,如果達到會增加相關文檔的評分,並不會改變查詢的結果。
GET bank/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"address": "mill"
}
},
{
"match": {
"gender": "M"
}
}
],
"must_not": [
{"match": {
"age": "28"
}}
],
"should": [
{
"match": {
"lastname": "Holland"
}
}
]
}
}
}
查詢-filter過濾
並不是所有的查詢都需要產生分數,特別是那些僅用於 「filtering」(過濾)的文檔。為了不計算分數 Elasticsearch 會自動檢查場景並且優化查詢的執行。
GET bank/_search
{
"query": {
"bool": {
"must": [
{
"range": {
"age": {
"gte": 18,
"lte": 30
}
}
},
{
"match": {
"address": "mill"
}
}
]
}
}
}
GET bank/_search
{
"query": {
"bool": {
"filter": [
{
"range": {
"age": {
"gte": 18,
"lte": 30
}
}
}
]
}
}
}
查詢-term
和 match 一樣。匹配某個屬性的值。全文檢索欄位用 match,其他非 text 欄位匹配用 term。
# 檢索時 非text欄位則使用term
GET bank/_search
{
"query": {
"term": {
"balance": "32838"
}
}
}
GET bank/_search
{
"query": {
"match": {
"balance": "32838"
}
}
}
Aggregations
Aggregations結構:
"aggregations" : {
"<aggregation_name>" : {
"<aggregation_type>" : {
<aggregation_body>
}
[,"meta" : { [<meta_data_body>] } ]?
[,"aggregations" : { [<sub_aggregation>]+ } ]?
}
[,"<aggregation_name_2>" : { ... } ]*
}
Aggregations範例:
# 搜索 address 中包含mill的所有人的年齡分布以及平均年齡,但不顯示這些人的詳情
GET bank/_search
{
"query": {
"match": {
"address": "mill"
}
},
"aggs": {
"ageAgg": {
"terms": {
"field": "age",
"size": 10
}
},
"ageAvg":{
"avg":{
"field":"age"
}
},
"balanceAvg":{
"avg": {
"field": "balance"
}
}
},
"size": 0
}
# 按照年齡聚合,並且請求這些年齡段的這些人的平均薪資
GET bank/_search
{
"query": {
"match_all": {}
},
"aggs": {
"ageAgg": {
"terms": {
"field": "age",
"size": 100
},
"aggs": {
"ageAvg": {
"avg": {
"field": "balance"
}
}
}
}
}
}
# 查出所有年齡分布,並且這些年齡段中 M 的平均薪資和 F 的平均薪資以及這個年齡段的總體平均薪資
GET bank/_search
{
"query": {
"match_all": {}
},
"aggs": {
"ageAgg": {
"terms": {
"field": "age",
"size": 100
},
"aggs": {
"genderAgg": {
"terms": {
"field": "gender.keyword",
"size": 10
},
"aggs": {
"balanceAvg": {
"avg": {
"field": "balance"
}
}
}
},
"ageBalanceAvg":{
"avg": {
"field": "balance"
}
}
}
}
}
}
Mapping
Mapping 是用來定義一個文檔(document),以及它所包含的屬性(field)是如何存儲和索引的。
查看索引
# 查看 mapping 資訊 kibana dev Tools執行
GET bank/_mapping
創建索引
創建索引-創建索引並指定映射
PUT /my_index
{
"mappings": {
"properties": {
"age": {"type": "integer"},
"email": {"type": "keyword"},
"name": {"type": "text"}
}
}
}
添加新欄位映射
# 添加新欄位映射
PUT /my_index/_mapping
{
"properties":{
"employee_id":{
"type":"keyword",
"index":false
}
}
}
更新映射
對於已經存在的映射欄位,我們不能更新。更新必須創建新的索引進行數據遷移
# 查看存在映射
GET /my_index/_mapping
GET /bank/_search
# 更新索引映射
PUT /newbank
{
"mappings": {
"properties": {
"account_number": {
"type": "long"
},
"address": {
"type": "text"
},
"age": {
"type": "integer"
},
"balance": {
"type": "long"
},
"city": {
"type": "keyword"
},
"email": {
"type": "keyword"
},
"employer": {
"type": "keyword"
},
"firstname": {
"type": "text"
},
"gender": {
"type": "keyword"
},
"lastname": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"state": {
"type": "keyword"
}
}
}
}
# 獲取新索引
GET /newbank/_mapping
數據遷移
先創建出 new_twitter的正確映射。
數據遷移格式:
# elasticsearch 新版本數據遷移
POST _reindex [固定寫法]
{
"source": {
"index": "twitter"
},
"dest": {
"index": "new_twitter"
}
}
# elasticsearch 老版本數據遷移
# 舊索引的 type 下的數據進行遷移
POST _reindex
{
"source": {
"index": "twitter",
"type": "tweet"
},
"dest": {
"index": "tweets"
}
}
數據遷移:
# 查看存在映射
GET /my_index/_mapping
GET /bank/_search
# 更新索引映射
PUT /newbank
{
"mappings": {
"properties": {
"account_number": {
"type": "long"
},
"address": {
"type": "text"
},
"age": {
"type": "integer"
},
"balance": {
"type": "long"
},
"city": {
"type": "keyword"
},
"email": {
"type": "keyword"
},
"employer": {
"type": "keyword"
},
"firstname": {
"type": "text"
},
"gender": {
"type": "keyword"
},
"lastname": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"state": {
"type": "keyword"
}
}
}
}
GET /newbank/_mapping
# 數據遷移 老版本遷移
POST _reindex
{
"source": {
"index": "bank",
"type": "account"
},
"dest": {
"index": "newbank"
}
}
GET /newbank/_search
# 不用type 老數據可以遷移過來
分詞
一個 tokenizer(分詞器)接收一個字元流,將之分割為獨立的 tokens(詞元,通常是獨立的單詞),然後輸出 tokens 流。
例如,whitespace tokenizer 遇到空白字元時分割文本。它會將文本 “Quick brown fox!” 分割為[Quick, brown, fox!]。
該 tokenizer(分詞器)還負責記錄各個 term(詞條)的順序或 position 位置(用於 phrase 短語和 word proximity 詞近鄰查詢),以及 term(詞條)所代表的原始 word(單詞)的 start
(起始)和 end(結束)的 character offsets(字元偏移量)(用於高亮顯示搜索的內容)。Elasticsearch 提供了很多內置的分詞器,可以用來構建custom analyzers(自定義分詞器)。
# 支援英文分詞器 對中文的分詞不友好
POST _analyze
{
"analyzer": "standard",
"text": "The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."
}
安裝IK分詞器
# wget下載 /mydata/elasticsearch/plugin
$ wget //github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.4.2/elasticsearch-analysis-ik-7.4.2.zip
# 進入docker容器
$ docker exec -it elasticsearch /bin/bash
$ cd /bin/
$ elasticsearch-plugin
$ elasticsearch-plugin -h
# 列出系統的分詞器
$ elasticsearch-plugin list
# 重啟容器
$ docker restart elasticsearch
測試IK分詞器
# ik分詞器
POST _analyze
{
"analyzer": "ik_max_word",
"text": "我是中國人"
}
# ik分詞器
POST _analyze
{
"analyzer": "ik_smart",
"text": "我是中國人"
}
自定義詞庫
修改/mydata/elasticsearch/plugins/elasticsearch-analysis-ik-7.4.2/config中的 IKAnalyzer.cfg.xml
# IKAnalyzer.cfg.xml 配置文件內容
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "//java.sun.com/dtd/properties.dtd">
<properties>
<comment>IK Analyzer 擴展配置</comment>
<!--用戶可以在這裡配置自己的擴展字典 -->
<entry key="ext_dict"></entry>
<!--用戶可以在這裡配置自己的擴展停止詞字典-->
<entry key="ext_stopwords"></entry>
<!--用戶可以在這裡配置遠程擴展字典 -->
<!-- <entry key="remote_ext_dict">words_location</entry> -->
<!--用戶可以在這裡配置遠程擴展停止詞字典-->
<!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>
添加自定義詞庫:
# 獲取 自定義詞庫的地址 一般是安裝在nginx上
//192.168.188.128/es/fenci.txt
# IK config配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "//java.sun.com/dtd/properties.dtd">
<properties>
<comment>IK Analyzer 擴展配置</comment>
<!--用戶可以在這裡配置自己的擴展字典 -->
<entry key="ext_dict"></entry>
<!--用戶可以在這裡配置自己的擴展停止詞字典-->
<entry key="ext_stopwords"></entry>
<!--用戶可以在這裡配置遠程擴展字典 -->
<entry key="remote_ext_dict">//192.168.188.128/es/fenci.txt</entry>
<!--用戶可以在這裡配置遠程擴展停止詞字典-->
<!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>
# 重啟elasticsearch、nginx
$ docker restart elasticsearch
$ docker restart nginx