全文搜尋引擎 Elasticsearch
寫在前面
最近在學Elasticsearch ,
我相信只要是接觸過開發的都會聽過Elasticsearch或ELK這麼一個技術。
主要用來做全文檢索或大資料分析等,之前一直處理了解狀態。
所以打算系統學學Elasticsearch ,這也算是我從零學習Elasticsearch的筆記吧。
1. Elasticsearch 術語介紹
1.1 文件Document
- 使用者儲存在es中的資料文件
- es儲存資料的最小單元
- 類比於資料庫一行資料
1.2 索引Index
-由相同欄位的文件列表組成
- 類比於資料庫中的表
ps: es6.0版本之前,索引下面可以新建多個Type,就把這個Index類比於database,
但是在,6.0版本之後,一個索引下面只能夠新建一個Type ,所以類比於表更合適
1.3 節點Node
- 一個ES的執行例項,是叢集的基本單元
1.4 叢集Cluser
- 有一個或多個節點組成,對外提供服務
2.Document 介紹
Document 主要就是一個Json Object
json物件有一些欄位(Field)組成,常見資料型別:
- 字串 :text , keywork
- 數值型 :long , integer , byte ,double , float , half_float(節省空間) , scaled_float(節省空間)
- 布林: boolean
- 日期:date
- 二進位制 : binary
- 範圍型別 (新的型別): integer_range , float_range , long_tange , double_range, date_range
注意:每一個文件Document都有一個唯一的ID標識
- 可以自行指定
- es 自動生成
示例Document
{ "remote_ip":"123.207.226.36", "user_name":"liuge", "@timestamp":"2015-05-14T08:23:52.000Z", "request_action":"GET", "http_version":"1.1", "response":"304", "bytes":"0", "referrer":"-", "agent":"-" }
每一個Document都有一個MetaData (元資料)
元資料:用於標註文件的相關資訊
- _index:文件所在的索引名
- _type: 文件所在的型別名
id:文件的唯一ID
uid:組合id,由_type和_id組成(6.X版本_type不再起作用)- _source:文件的原始Json資料,可以從這裡獲取每一個欄位的內容
- _all:整合所有欄位的內容到該欄位,預設禁用,不推薦
3.Index (索引) 介紹
類比於table,具有相同結構文件的集合
- 每個索引都有自己的 mapping 定義 , 用於定義欄位名和型別
一個叢集可以有多個索引
3.RESTful API 介紹
es叢集對外提供RESTful API:使用者操作叢集中的資料
- 表現層 狀態 轉移
- URI 指定資源 ,如:Index ,Document
- Http Method 指明資源操作型別,如:GET,POST,PUT,DELETE等
與es叢集資源進行互動的方式:
方式一:Curl命令列
curl -XPUT "HTTP://localhost:9200/ceshi/doc/1" -i -H "Content-Type:application/json" -d ' { "username":"liuge", "job":"軟體開發" } '
方式二:Kibana DevTools
PUT /ceshi/doc/1 { "useranme":"liuge", "job":"軟體開發" }
4.Mapping 介紹
Mapping設定,即如何定義資料欄位和型別
==========Mapping的欄位型別(Filed type)=========================== 核心資料型別: - 字串 :text (會分詞), keywork(不會分詞) - 數值型 :long , integer , byte ,double , float , half_float(節省空間) , scaled_float(節省空間) - 布林: boolean - 日期:date - 二進位制 : binary - 範圍型別 (新的型別): integer_range , float_range , long_tange , double_range, date_range 複雜的資料型別: - 陣列型別 array - Object - 巢狀型別 nested object 地理位置資料型別: - geo_point - geo_shape 專用型別: - 記錄ip地址 - 實現自動補全completion - 記錄分次數 token_count - 記錄字串 hash - percolator 多欄位特性: - 允許對同一個欄位採用不同的配置,比如分詞,常見的實現漢字實現拼音搜尋 - 實現方式:在漢字中新增一個子欄位為pinyin就可以
Kibana DevTools方式:(推薦)
4.1 自定義一個mapping
PUT accounts { "settings": { "index": { "number_of_shards" : 1, "number_of_replicas" : 0 } }, "mappings":{ "doc":{ "dynamic":false, # 設定不允許動態新增,結果是,可以插入未定義的欄位,但是不能通過未定義欄位值來進行查詢 "properties":{ "user": { "type": "text", "analyzer": "ik_max_word", "search_analyzer": "ik_max_word" }, "title": { "type": "text", "analyzer": "ik_max_word", "search_analyzer": "ik_max_word" }, "desc": { "type": "text", "analyzer": "ik_max_word", "search_analyzer": "ik_max_word" } } } } }
上面程式碼中,首先新建一個名稱為accounts的 Index
這三個欄位都是中文,而且型別都是文字(text),所以需要指定中文分詞器,不能使用預設的英文分詞器。
Elastic 的分詞器稱為 analyzer。我們對每個欄位指定分詞器。
"user": { "type": "text", "analyzer": "ik_max_word", "search_analyzer": "ik_max_word" }
上面程式碼中,analyzer是欄位文字的分詞器,search_analyzer是搜尋詞的分詞器。ik_max_word分詞器是外掛ik提供的,可以對文字進行最大數量的分詞。
4.2 新增記錄,帶上id
PUT accounts/doc/1 { "user": "張三", "title": "工程師", "desc": "資料庫管理" }
新增記錄的時候,也可以不指定 Id,這時要改成 POST 請求
POST accounts/doc
{ "user": "李四", "title": "工程師", "desc": "系統管理" }
4.3 刪除資料
DELETE accounts/doc/1
DELETE accounts
4.4更新記錄就是使用 PUT 請求,重新發送一次資料。
PUT accounts/doc/1
{
"user": "張三",
"title": "工程師",
"desc": "資料庫管理,軟體開發"
}
4.3 查詢資料
使用 GET 方法,直接請求/Index/Type/_search,就會返回所有記錄
GET accounts/doc/_search
/Index/Type/id ,返回指定id的記錄
GET accounts/doc/1
GET accounts/doc/_search
{
"query":{
"term":{
"_id":"1"
}
}
}
GET accounts/doc/_search { "query" : { "match" : { "desc" : "管理" } }, "from": 1, "size": 1 }
上面程式碼使用 Match 查詢,指定的匹配條件是desc欄位裡面包含"軟體"這個詞
Elastic 預設一次返回10條結果,可以通過size欄位改變這個設定。
還可以通過from欄位,指定位移。
上面程式碼指定,從位置1開始(預設是從位置0開始),只返回一條結果。
邏輯運算or
GET accounts/doc/_search { "query" : { "match" : { "desc" : "軟體 系統" }} }
邏輯運算and
GET accounts/doc/_search { "query": { "bool": { "must": [ { "match": { "desc": "軟體" } }, { "match": { "desc": "系統" } } ] } } }
5 分詞介紹
5.1 Analysis
分詞是指將文字轉為一系列單詞的過程,也叫作文字分析
在es裡面稱為Analysis
在es中專門負責分詞的元件叫做分詞器(Analyzer)
分詞器(Analyzer),es會自帶一部分詞器
- Character Filters
- 針對原始的文字進行處理,例如,去除html,a,p,div特殊符號等
- Tokenizer
- 將原始的文字按照一定的規則切分為單詞
- Token Filters
- 把Tokenizer再加工,大小寫轉換等,沒有實際意義的詞可以去掉,新增近義詞,同義詞等
ps:分詞執行的順序也是從上到下的
5.2 分詞API的使用
Analyze(分詞) API 使用
es提供的用於測試分詞的api介面,驗證分詞效果
- 可以直接指定分詞器(Analyzer)進行測試
POST _analyze
{
"analyzer":"standard", #這個測試用的standard分詞器是es自己帶的
"text":"Hello World!"
}
- 可以直接指定索引中的欄位進行測試 POST test_index/_analyze { "field":"username", # 指定索引(表)的欄位 "text":"hello world!" } - 可以自定義分析器進行測試 POST _analyze { "analyzer":"standard", #指明自己使用哪一個分詞器 "filter":["lowercase"], #指明filter處理為小寫 "text":"HEllo WOrld!" }
5.3 預定義分詞器
es中自帶的分詞器
如下:分詞器前面講到,就是由三個部分組成,這裡自帶的不同也是三個部分組成上不同
- standard Analyzer - 預設分詞器,按照單詞的邊界切分 - Tokenizer 1.standard - Token Filters : 1.standard 2.Loswer case 3.Stop(預設禁用) - Simple Analyzer - 切分規則。按照非字母切分,非字母的部分會被刪除 - Filters 1.Loswer case - Whitespace Analyzer - 按照空格進行切分 - Stop Analyzer - 語氣助詞等修飾性詞語會被移除,比如,the ,an ,的,這那等 - 相比於Simple Analyzer 多了修飾性詞語的移除 - Filters1.Loswer case 2.stop - Keyword Analyzer - 不進行分詞操作 - 原樣輸出,當你不想對文字做分詞操作的時候 - Pattern Analyzer - 自定義切分的規則,正則匹配 - 預設是 \W+ ,即非字詞的符號作為分隔符,空格 ~ = ‘ 等特殊符號 - Language Analyzer - 提供了30+ 常見語言的分詞器 中文分詞:是指將一句中文句子切分為一個個單獨的詞 在英文中,句子內單詞可以使用空格做明顯分隔, 在中文中,句子內的詞語是沒有分隔的 常見中文分詞系統: - IK - jieba 高階一點的:基於自然語言處理的分詞系統 - Hanlp - THULAC
5.4 自定義分詞器
當自帶的分詞器無法滿足需求的時候,可以自定義分詞
通過自定義分詞的三個部分來實現:
- Character Filters
- Tokenizer
- Token Filters
5.4.1 Character Filters
- 針對原始的文字進行處理,例如,去除html,a,p,div特殊符號等
自帶的如下:
- HTML Script 去除html 標籤和轉換html實體
- Mapping 進行字串的替換操作
- Pattern Replace進行正則匹配替換
會影響到Tokenizer解析position和offset
5.4.2 Tokenizer
-將原始文字按照一定規則切分為單詞
自帶的如下:
- standard按照單詞進行分割
- latter 按照非字元類進行分割
- whitespace 按照空格進行分割
- UAX URL Email 按照standard 分割 ,但不會分割郵箱和URL
- NGram 和Edge NGram 連詞分割
- Path Hierachy 按照檔案路徑進行分割
測試:
POST _analyze{ "tokenizer":"path_hierachy", "text":"/one/two/three" }
5.4.3 Token Filters
- 將tokenizer 輸出的單詞(term )進行增加,刪除,修改等操作
自帶的如下:
- lowercase 將所有輸出的單詞轉換為小寫
- stop 刪除 stop words
- NGram 和 Edge Ngram 連詞分割
- Synonym 新增近義詞的term
重要,這裡可以實現自動補全的功能
POST _analyze{ "text":"a Hello World!", "tokenizer":"standard", "filter":[ "stop",# 當有多個filter的時候,會依次執行 "lowercase", { "type":"ngram", "min_gram":2, "max_gram":4 } ] }
5.5 自定義分詞的API
自定義分詞器在索引(具體表)中的設定:
PUT test_index{ "settings":{ "analysis":{ "char_filter":{}, "tokenizer":{}, "filter":{}, "analyzer":{} } } }
demo
PUT testairbnb { "settings": { "index": { "number_of_shards": 1, "number_of_replicas": 0, "analysis": { "analyzer": { "autosuggest_analyzer": { "filter": [ "lowercase", "asciifolding", "autosuggest_filter" ], "tokenizer": "standard", "type": "custom" }, "ngram_analyzer": { "filter": [ "lowercase", "asciifolding", "ngram_filter" ], "tokenizer": "standard", "type": "custom" } }, "filter": { "autosuggest_filter": { "max_gram": "20", "min_gram": "1", "token_chars": [ "letter", "digit", "punctuation", "symbol" ], "type": "edge_ngram" }, "ngram_filter": { "max_gram": "9", "min_gram": "2", "token_chars": [ "letter", "digit", "punctuation", "symbol" ], "type": "ngram" } } } } }, "mappings": { "doc": { "dynamic": false, "properties": { "accommodates": { "type": "integer" }, "bathrooms": { "type": "integer" }, "bed_type": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "bedrooms": { "type": "integer" }, "beds": { "type": "integer" }, "date_from": { "type": "date", "format": "yyyyMMdd" }, "date_to": { "type": "date", "format": "yyyyMMdd" }, "has_availability": { "type": "boolean" }, "host_image": { "type": "keyword", "ignore_above": 256, "index": false }, "host_name": { "type": "text", "analyzer": "autosuggest_analyzer", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "image": { "type": "keyword", "ignore_above": 256, "index":false }, "listing_url": { "type": "keyword", "ignore_above": 256 }, "location": { "type": "geo_point" }, "name": { "type": "text", "analyzer": "autosuggest_analyzer", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "price": { "type": "float" }, "property_type": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "room_type": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } } } } } }
上面分詞的配置中,能夠完全實現個性化設定
參考文章http://www.ruanyifeng.com/blog/2017/08/elasticsearch.html
參考文章https://coding.imooc.com/class/chapter/181.html