前言
Elasticsearch 是一個非常強大的搜索引擎。它目前被廣泛地使用于各個 IT 公司。Elasticsearch 是由 Elastic 公司創(chuàng)建。它的代碼位于 GitHub - elastic/elasticsearch: Free and Open, Distributed, RESTful Search Engine。目前,Elasticsearch 是一個免費及開放(free and open)的項目。同時,Elastic 公司也擁有 Logstash 及 Kibana 開源項目。這個三個項目組合在一起,就形成了 ELK 軟件棧。他們?nèi)齻€共同形成了一個強大的生態(tài)圈。簡單地說,Logstash 負(fù)責(zé)數(shù)據(jù)的采集,處理(豐富數(shù)據(jù),數(shù)據(jù)轉(zhuǎn)換等),Kibana 負(fù)責(zé)數(shù)據(jù)展示,分析,管理,監(jiān)督及應(yīng)用。Elasticsearch 處于最核心的位置,它可以幫我們對數(shù)據(jù)進(jìn)行快速地搜索及分析。
一、什么是elasticsearch
1. mysql搜索面臨的問題
- 性能低下
- 沒有相關(guān)性排名–剛需
- 無法全文搜索
- 搜索不準(zhǔn)確–沒有分詞
2. 什么是全文搜索
我們生活中的數(shù)據(jù)總體分為兩種:結(jié)構(gòu)化數(shù)據(jù)和非結(jié)構(gòu)化數(shù)據(jù)。
- 結(jié)構(gòu)化數(shù)據(jù):指具有固定格式或有限長度的數(shù)據(jù),如數(shù)據(jù)庫,元數(shù)據(jù)等。
- 非結(jié)構(gòu)化數(shù)據(jù):指不定長或無固定格式的數(shù)據(jù),如郵件,word文檔等。
非結(jié)構(gòu)化數(shù)據(jù)又一種叫法叫全文數(shù)據(jù)。
按照數(shù)據(jù)的分類,搜索也分為兩種:
- 對結(jié)構(gòu)化數(shù)據(jù)的搜索:如對數(shù)據(jù)庫的搜索,用SQL語句。再如對元數(shù)據(jù)的搜索,如利用windows搜索對文件名,類型,修改時間進(jìn)行搜索等。
- 對非結(jié)構(gòu)化數(shù)據(jù)的搜索:如利用windows的搜索也可以搜索文件內(nèi)容,Linux下的grep命令,再如用Google和百度可以搜索大量內(nèi)容數(shù)據(jù)。
對非結(jié)構(gòu)化數(shù)據(jù)也即對全文數(shù)據(jù)的搜索主要有兩種方法:
一種是順序掃描法(Serial Scanning):所謂順序掃描,比如要找內(nèi)容包含某一個字符串的文件,就是一個文檔一個文檔的看,對于每一個文檔,從頭看到尾,如果此文檔包含此字符串,則此文檔為我們要找的下一個文件,直到掃描完所有的文件。如利用windows的搜索也可以搜索文件內(nèi)容,只是相當(dāng)?shù)穆?。假如有一個80G硬盤,如果想在上面找到一個內(nèi)容包含某字符串的文件,可能需要幾個小時的時間。Linux下的grep命令也是這一種方式。這是一種比較原始的方法,但對于小數(shù)據(jù)量的文件,這種方法還是最直接,最方便的。但是對于大量的文件,這種方法的速度就很慢。
另一種是全文檢索(Full-text Search):即先建立索引,再對索引進(jìn)行搜索。索引是從非結(jié)構(gòu)化數(shù)據(jù)中提取出之后重新組織的信息。
3.什么是elasticsearch
Elasticsearch是一個分布式可擴展的實時搜索和分析引擎,一個建立在全文搜索引擎Apache Lucene?基礎(chǔ)上的搜索引擎.當(dāng)然Elasticsearch并不僅僅是Lucene那么簡單,它不僅包括了全文搜索功能,還可以進(jìn)行以下工作:
- 分布式實時文件存儲,并將每一個字段都編入索引,使其可以被搜索。
- 實時分析的分布式搜索引擎。
- 可以擴展到上百臺服務(wù)器,處理PB級別的結(jié)構(gòu)化或非結(jié)構(gòu)化數(shù)據(jù)。
ES的適用場景
- 維基百科
- The Guardian、新聞
- Stack Overflow
- Github
- 電商網(wǎng)站、檢索商品
- 日志數(shù)據(jù)分析、logstash采集日志、ES進(jìn)行復(fù)雜的數(shù)據(jù)分析(ELK)
- 商品價格監(jiān)控網(wǎng)站、用戶設(shè)定價格閾值
- BI系統(tǒng)、商業(yè)智能、ES執(zhí)行數(shù)據(jù)分析和挖掘
ES特點
- 可以作為一個大型的分布式集群(數(shù)百臺服務(wù)器)技術(shù),處理PB級數(shù)據(jù),服務(wù)大公司,可以運行在單機上,服務(wù)小公司。
- ES不是什么新技術(shù),主要是將全文檢索、數(shù)據(jù)分析以及分布式技術(shù)合并在一起,才形成了獨一無二的ES.lucene (全文檢索)、商用的數(shù)據(jù)分析軟件、分布式數(shù)據(jù)庫(mycat)
- 對用戶而言,是開箱即用,非常簡單,作為中小型的應(yīng)用,直接3分鐘部署ES,就可以作為生產(chǎn)環(huán)境的系統(tǒng)使用,數(shù)據(jù)量不大,操作不是很復(fù)雜。
- 數(shù)據(jù)庫的功能面對很多領(lǐng)域是不夠用的(事務(wù),還有各種聯(lián)機事務(wù)的操作):特殊的功能,比如全文檢索、同義詞處理、相關(guān)度排名、復(fù)雜數(shù)據(jù)分析、海量數(shù)據(jù)近實時處理;ES作為傳統(tǒng)數(shù)據(jù)庫的一個補充,提供了數(shù)據(jù)庫所不能提供的很多功能。
二、elasticsearch和kibana安裝
kibana相當(dāng)于是elasticsearch的可視化工具
1. 關(guān)閉并禁用防火墻
systemctl stop firewalld.service
systemctl disable firewalld.service
systemctl status firewalld.service
2. 通過docker安裝elasticsearch
#新建es的config配置文件夾
mkdir -p /data/elasticsearch/config
#新建es的data目錄
mkdir -p /data/elasticsearch/data
#給目錄設(shè)置權(quán)限
chmod 777 -R /data/elasticsearch
#寫入配置到elasticsearch.yml中
echo "http.host: 0.0.0.0" >>/data/elasticsearch/config/elasticsearch.yml
#安裝es
docker run --name elasticsearch -p 9200:9200 -p 9300:9300 \
-e "discovery.type=single-node" \
-e ES_JAVA_OPTS="-Xms128m -Xmx256m" \
-v /data/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /data/elasticsearch/data:/usr/share/elasticsearch/data \
-v /data/elasticsearch/plugins:/usr/share/elasticsearch/plugins \
-d elasticsearch:7.10.1
3. 通過docker安裝kibana
將ip改為自己的ip 不能用127.0.0.1 因為它是docker kibana版本號要和elasticsearch版本號一致
docker run -d --name kibana -e ELASTICSEARCH_HOSTS="http://192.168.10.130:9200" -p 5601:5601 kibana:7.10.1
訪問ip:5601
三、es中的基本概念
es中的type、index、mapping和dsl
快速的用mysql來理解elasticsearch 對應(yīng)如下
1. 索引
有兩個含義:動詞(insert) - 名詞(表)
Elasticsearch將它的數(shù)據(jù)存儲到一個或者多個索引(index)中,索引就像數(shù)據(jù)庫,可以向索引寫入文檔或者從索引中讀取文檔。
PUT /movies/movie/1
{
"title": "The Godfather",
"director": "Francis Ford Coppola",
"year": 1972,
"genres": ["Crime","Drama"]
}
2. 文檔
文檔(document)是Elasticsearch中的主要實體。所以,所有使用Elasticsearch最終都會歸結(jié)到文檔的搜索上從客戶端看,文檔就是一個JSON對象,文檔由字段構(gòu)成,每個字段包含字段名以及一個或多個字段值。文檔之間可能有各自不同的字段集合,文檔沒有固定的模式或強制的結(jié)構(gòu)。
3. 類型(7.x開始取消)
Elasticsearch中每個文檔都有與之對應(yīng)的類型(type)定義,允許在一個索引存儲多種文檔類型,并提供不同映射。
4. 映射
映射做的就是,存儲分析鏈所需的信息。
主要就是設(shè)置一些參數(shù),根據(jù)這些參數(shù)來做過濾還是分割詞條。
四、通過put和post方法添加數(shù)據(jù)
官方文檔:https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html
因為es的調(diào)用是基于Restful的設(shè)計風(fēng)格 所以直接用kibana自帶的請求方式 或者用postman、apifox等直接發(fā)起get post等請求就可以實現(xiàn) 這里用kibana自帶的請求方式 (Dev Tools) 便于觀察
查看所有索引:
1. 通過put+id新建數(shù)據(jù)
在customer
下保存id
為1的數(shù)據(jù),這里id
是必須的
在7.x以前一般都是有type的 現(xiàn)在用
_doc
這種固定格式 然后+id
put {index}/_doc/{id} //index可以不用提前建好 會默認(rèn)創(chuàng)建
put操作必須加id
post操作可以不加 然后返回的值里result
會指明這是新建的還是修改的
GET _cat/indices
PUT /account/_doc/1
{
"name": "bobby",
"age": 18,
"company": [
{
"name":"imooc",
"address":"shanghai"
},
{
"name":"imooc2",
"address":"shanghai"
}
]
}
“_version”、“_seq_no”和“_primary_term”之間的關(guān)系:https://discuss.elastic.co/t/relation-between-version-seq-no-and-primary-term/179647
2. 發(fā)送post不帶id的數(shù)據(jù)
如果post
帶id
的話那就和put
的邏輯一樣了
3. post+_create
目的:沒有就創(chuàng)建,有就報錯
4. 查看index
GET _cat/indices //查看所有索引
GET /account //查看index的基本信息
五、通過url和query boby查詢數(shù)據(jù)
1. 獲取數(shù)據(jù)
_doc是詳情 _source是只獲取數(shù)據(jù)
2. 搜索數(shù)據(jù)
官方文檔:https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html
Elasticsearch有兩種查詢方式
-
URI帶有查詢條件 (輕量查詢)
查詢能力有限,不是所有的查詢都可以使用此方式 - 請求體中帶有查詢條件 (復(fù)雜查詢)
查詢條件以JSON格式表現(xiàn),作為查詢請求的請求體,適合復(fù)雜的查詢
通過url查詢:
查詢所有index
所包含的
數(shù)據(jù)是放在hits
里面的
max_score
是一個得分 數(shù)據(jù)里哪一個數(shù)據(jù)和我們搜索的數(shù)據(jù)匹配度多大
通過request boby查詢數(shù)據(jù)
六、更新和刪除數(shù)據(jù)
1. 想要給已有的數(shù)據(jù)新增字段
使用_doc
來更新會發(fā)現(xiàn)是覆蓋操作
得用_update
來進(jìn)行操作
如果用_update
更新的值和你輸入的值相同 那么不會產(chǎn)生任何變化 version
也不會變化 _doc
會更新version
(_doc是愣頭青 只會更新 不會查這個值有沒有)
2. 刪除數(shù)據(jù)和索引
刪除一個“表”
刪除整個index
七、批量插入和批量查詢
1. 批量操作(bulk)
可以有不同的操作 index delete update等
index update post put操作的時候是有兩行的 第一行是index和id 第二行是數(shù)據(jù) 其他的是一行
官方給的測試數(shù)據(jù):https://github.com/elastic/elasticsearch/blob/7.5/docs/src/test/resources/accounts.json
POST _bulk
{ "index" : { "_index" : "test", "_id" : "1"}}
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_jid": "2"}}
{ "create" : { "_index" : "test", "_id" : "3"}}
{ "field1" : "value3"}
{ "update" : {"_id" : "1", "_index" : "test"}}
{ "doc" : { "field2" : "value2"]}
每一次操作是互不影響的 比如第一次失敗了 下一步還是會操作的 沒有事務(wù)
2. 批量獲取(mget)
比如獲取user的index
和account的index
里id
為1
的值
八、倒排索引
es里query的查詢和mysl中l(wèi)ike查詢的邏輯是完全不一樣的
比如我要存儲
6:“671 Bristol Street”
13:“789 Madison Street”
這時候es就會進(jìn)行分詞 分完詞以后進(jìn)行和文檔的整理 整理出你的key和次數(shù) 第幾個 等等等等
查詢的時候 比如我要查詢:
6:“Bristol Street”
他會進(jìn)行分詞后查詢 并不是全等于才返回 而是有單詞等于就返回 類似于百度引擎 然后會有一個“得分”的概念 返回 基于得分來分析返回的數(shù)據(jù)
九、query dsl查詢
查詢一般簡單查詢和復(fù)雜查詢
簡單查詢就是拼湊URI
復(fù)雜查詢是最完整的查詢 就是基于request body的查詢
1. 一個完整的查詢語句應(yīng)該如何寫
官方文檔:https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html
基本的分頁語法結(jié)構(gòu):
query(條件)是最復(fù)雜的
官方文檔:https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query.html
官方支持的dsl查詢方法有:
重點關(guān)注全文查詢
、復(fù)合查詢
、術(shù)語級查詢(term)
即可
2. 全文查詢
(1) match查詢(匹配查詢)
match:模糊匹配,需要指定字段名,但是輸入會進(jìn)行分詞,比如"hello world"會進(jìn)行拆分為hello和world,然后匹配,如果字段中包含hello或者world,或者都包含的結(jié)果都會被查詢出來,也就是說match是一個部分匹配的模糊查詢。查詢條件相對來說比較寬松。
查詢address里面包含street
(2) match_phrase查詢(短語查詢)
官方文檔:https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query-phrase.html
match_phase:會對輸入做分詞,但是需要結(jié)果中也包含所有的分詞,而且順序要求一樣。以""hello
world"為例,要求結(jié)果中必須包含hello和world,而且還要求他們是連著的,順序也是固定的,hello that word不滿足,world hello也不滿足條件。
(3) multi_match查詢(多個字段查詢)
官方文檔:https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-multi-match-query.html
multi_match 查詢提供了一個簡便的方法用來對多個字段執(zhí)行相同的查詢,即對指定的多個字段進(jìn)行
match查詢 - 比如我想查找title
或者desc
中包含“go”的字段
如果我想讓title
的權(quán)重(得分) 更高一些就使用^
GET resume/_search
{
"query":{
"multi_match": {
"query": "go",
"fields": ["title^2","desc"]
}
}
}
(4) query_string查詢(所有字段查詢)
官方文檔:https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html
query_string:和match類似,但是match需要指定字段名,query_string是在所有字段中搜索,范圍更廣泛。
default_field字段如果不用的話默認(rèn)是所有*
,指定字段的話和上面的差不多 query里可以加連接符:AND
OR
等等
這個query_string在查詢的時候多了一步,就是解析query字段里的連接符 這種寫法會更嚴(yán)謹(jǐn)一些 更復(fù)雜 更自由
(5) match all查詢(全文查詢)
這個在開頭用過了 也是最簡單的一個 直接貼代碼吧
3. term 級別查詢
官方文檔:https://www.elastic.co/guide/en/elasticsearch/reference/current/term-level-queries.html
(1) term查詢 - 原生
term : 這種查詢和match在有些時候是等價的,比如我們查詢單個的詞hello,那么會和match查詢結(jié)果一
樣,但是如果查詢"hello world",結(jié)果就相差很大,因為這個輸入不會進(jìn)行分詞,就是說查詢的時候,是
查詢字段分詞結(jié)果中是否有"hello world"的字樣,而不是查詢字段中包含"hello world"的字樣,
elasticsearch會對字段內(nèi)容進(jìn)行分詞,“hello world"會被分成hello和world,不存在"hello world”,因此這
里的查詢結(jié)果會為空。這也是term查詢和match的區(qū)別。
(2) range查詢 - 范圍查詢
(3) exists查詢(是否存在)
查詢所有 有age字段的數(shù)據(jù)
(4) fuzzy模糊查詢 - 糾錯
我在百度想要搜索golang
但是我不知道golang
怎么拼 寫成了golanl
百度會有一個糾錯的功能 會給我們搜索golang
而不是golanl
這就是fuzzy查詢 涉及到一個編輯距離
的原理
編輯距離(一個算法題):https://www.nowcoder.com/questionTerminal/3959837097c7413a961a135d7104c314
理解這道題 自然而然就理解什么是編輯距離了
我一不小心將street
拼寫成了streat
如果是多個單詞的話 就在match
查詢中對內(nèi)容進(jìn)行更詳細(xì)的查詢:
4. 復(fù)合查詢
官方文檔:https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html
就是運用上述的所有邏輯做一個更復(fù)雜的查詢
Elasticsearch bool
查詢對應(yīng)Lucene BooleanQuery
, 格式如下
{
"query":{
"bool":{
"must":[
],
"should":[
],
"must_not":[
],
"filter":[
],
}
}
}
- must: 里面條件必須全部滿足 - 必須匹配,查詢上下?,加分
-
should: 里面條件滿足也行 不滿足也行 滿足的話
得分
會高一點,不滿足得分
會低一點 - 應(yīng)該匹配,查詢上下?,加分 -
must_not: 里面條件必須不能滿足 和
must
邏輯相反 - 必須不匹配,過濾上下?,過濾 - filter: 將里面的數(shù)據(jù)進(jìn)行過濾 過濾的規(guī)則和上面的邏輯差不多 - 必須匹配,過濾上下?,過濾
bool
查詢采用了一種匹配越多越好的方法,因此每個匹配的must
或should
子句的分?jǐn)?shù)將被加在一起,以提供每個文檔的最終得分
演示復(fù)合查詢:
無非就是把查詢語句組合一下而已
十、Mapping(類型定義)
官方文檔:https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html
1. 什么是 Mapping?
在帶你搞定 ElasticSearch
術(shù)語中,我們講到了 Mapping
類似于數(shù)據(jù)庫中的表結(jié)構(gòu)定義schema
,它有以下幾個作用:
定義索引中的字段的名稱定義字段的數(shù)據(jù)類型,比如字符串、數(shù)字、布爾字段,倒排索引的相關(guān)配置,比如設(shè)置某個字段為不被索引、記錄 position
等在 ES
早期版本,一個索引下是可以有多個 Type
,從 7.0開始,一個索引只有一個 Type
,也可以說一個 Type
有一個 Mapping
定義。
在了解了什么是 Mapping
之后,接下來對 Mapping
的設(shè)置做下介紹:
2. Mapping 設(shè)置
在創(chuàng)建一個索引的時候,可以對 dynamic
進(jìn)行設(shè)置,可以設(shè)成 false
、true
或者 strict
。
比如一個新的文檔,這個文檔包含一個字段,當(dāng) Dynamic
設(shè)置為 true
時,這個文檔可以被索引進(jìn) ES
,這個字段也可以被索引,也就是這個字段可以被搜索,Mapping
也同時被更新;當(dāng) dynamic
被設(shè)置為false
時候,存在新增字段的數(shù)據(jù)寫入,該數(shù)據(jù)可以被索引,但是新增字段被丟棄;當(dāng)設(shè)置成 strict
模式時候,數(shù)據(jù)寫入直接出錯。
另外還有 index
參數(shù),用來控制當(dāng)前字段是否被索引,默認(rèn)為 true
,如果設(shè)為 false
,則該字段不可被搜索。
參數(shù) index_options
用于控制倒排索引記錄的內(nèi)容,有如下 4 種配置:
- doc:只記錄 doc id
- freqs:記錄 doc id 和 term frequencies
- positions:記錄 doc id、term frequencies 和 term position
- offsets:記錄 doc id、term frequencies、term position 和 character offects
另外,text 類型默認(rèn)配置為 positions
,其他類型默認(rèn)為 doc,記錄內(nèi)容越多,占用存儲空間越大。null_value
主要是當(dāng)字段遇到 null 值時的處理策略,默認(rèn)為 NULL,即空值,此時 ES 會默認(rèn)忽略該值,
可以通過設(shè)定該值設(shè)定字段的默認(rèn)值,另外只有 KeyWord
類型支持設(shè)定 null_value
。copy_to
作用是將該字段的值復(fù)制到目標(biāo)字段,實現(xiàn)類似 _all
的作用,它不會出現(xiàn)在 _source
中,只用來搜索。
除了上述介紹的參數(shù),還有許多參數(shù),大家感興趣的可以在官方文檔中進(jìn)行查看。
在學(xué)習(xí)了 Mapping
的設(shè)置之后,讓我們來看下字段的數(shù)據(jù)類型有哪些吧!
3. 字段數(shù)據(jù)類型
ES 字段類型類似于 MySQL 中的字段類型,ES 字段類型主要有:核心類型、復(fù)雜類型、地理類型以及特殊類型,
核心類型
從圖中可以看出核心類型可以劃分為字符串類型、數(shù)字類型、日期類型、布爾類型、基于 BASE64 的二
進(jìn)制類型、范圍類型。
字符串類型
其中,在 ES 7.x 有兩種字符串類型:text 和 keyword,在 ES 5.x 之后 string 類型已經(jīng)不再支持了。
text 類型適用于需要被全文檢索的字段,例如新聞?wù)摹⑧]件內(nèi)容等比較長的文字,text 類型會被
Lucene 分詞器(Analyzer)處理為一個個詞項,并使用 Lucene 倒排索引存儲,text 字段不能被用于排
序,如果需要使用該類型的字段只需要在定義映射時指定 JSON 中對應(yīng)字段的 type 為 text。
keyword 適合簡短、結(jié)構(gòu)化字符串,例如主機名、姓名、商品名稱等,可以用于過濾、排序、聚合檢
索,也可以用于精確查詢。
數(shù)字類型
數(shù)字類型分為 long、integer、short、byte、double、float、half_float、scaled_float。
數(shù)字類型的字段在滿足需求的前提下應(yīng)當(dāng)盡量選擇范圍較小的數(shù)據(jù)類型,字段長度越短,搜索效率越高,
對于浮點數(shù),可以優(yōu)先考慮使用 scaled_float 類型,該類型可以通過縮放因子來精確浮點數(shù),例如 12.34
可以轉(zhuǎn)換為 1234 來存儲。
日期類型
在 ES 中日期可以為以下形式:
格式化的日期字符串,例如 2020-03-17 00:00、2020/03/17
時間戳(和 1970-01-01 00:00:00 UTC 的差值),單位毫秒或者秒即使是格式化的日期字符串,ES 底層
依然采用的是時間戳的形式存儲。
布爾類型
JSON 文檔中同樣存在布爾類型,不過 JSON 字符串類型也可以被 ES 轉(zhuǎn)換為布爾類型存儲,前提是字符
串的取值為 true 或者 false,布爾類型常用于檢索中的過濾條件。
二進(jìn)制類型
二進(jìn)制類型 binary 接受 BASE64 編碼的字符串,默認(rèn) store 屬性為 false,并且不可以被搜索。
范圍類型
范圍類型可以用來表達(dá)一個數(shù)據(jù)的區(qū)間,可以分為5種:
integer_range、float_range、long_range、double_range 以及 date_range。
復(fù)雜類型
復(fù)合類型主要有對象類型(object)和嵌套類型(nested):
對象類型
JSON 字符串允許嵌套對象,一個文檔可以嵌套多個、多層對象??梢酝ㄟ^對象類型來存儲二級文檔,不
過由于 Lucene 并沒有內(nèi)部對象的概念,ES 會將原 JSON 文檔扁平化,例如文檔:
實際上 ES 會將其轉(zhuǎn)換為以下格式,并通過 Lucene 存儲,即使 name 是 object 類型:
嵌套類型
嵌套類型可以看成是一個特殊的對象類型,可以讓對象數(shù)組獨立檢索,例如文檔:
username 字段是一個 JSON 數(shù)組,并且每個數(shù)組對象都是一個 JSON 對象。如果將 username 設(shè)置為
對象類型,那么 ES 會將其轉(zhuǎn)換為:
可以看出轉(zhuǎn)換后的 JSON 文檔中 first 和 last 的關(guān)聯(lián)丟失了,如果嘗試搜索 first 為 wu,last 為 xy 的文
檔,那么成功會檢索出上述文檔,但是 wu 和 xy 在原 JSON 文檔中并不屬于同一個 JSON 對象,應(yīng)當(dāng)是不匹配的,即檢索不出任何結(jié)果。
嵌套類型就是為了解決這種問題的,嵌套類型將數(shù)組中的每個 JSON 對象作為獨立的隱藏文檔來存儲,
每個嵌套的對象都能夠獨立地被搜索,所以上述案例中雖然表面上只有 1 個文檔,但實際上是存儲了 4
個文檔。
地理類型
地理類型字段分為兩種:經(jīng)緯度類型和地理區(qū)域類型:
經(jīng)緯度類型
經(jīng)緯度類型字段(geo_point)可以存儲經(jīng)緯度相關(guān)信息,通過地理類型的字段,可以用來實現(xiàn)諸如查找
在指定地理區(qū)域內(nèi)相關(guān)的文檔、根據(jù)距離排序、根據(jù)地理位置修改評分規(guī)則等需求。
地理區(qū)域類型
經(jīng)緯度類型可以表達(dá)一個點,而 geo_shape 類型可以表達(dá)一塊地理區(qū)域,區(qū)域的形狀可以是任意多邊
形,也可以是點、線、面、多點、多線、多面等幾何類型。
特殊類型
特殊類型包括 IP 類型、過濾器類型、Join 類型、別名類型等,在這里簡單介紹下 IP 類型和 Join 類型,
其他特殊類型可以查看官方文檔。
IP 類型
IP 類型的字段可以用來存儲 IPv4 或者 IPv6 地址,如果需要存儲 IP 類型的字段,需要手動定義映射:
Join 類型
Join 類型是 ES 6.x 引入的類型,以取代淘汰的 _parent 元字段,用來實現(xiàn)文檔的一對一、一對多的關(guān)
系,主要用來做父子查詢。
Join 類型的 Mapping 如下:
其中,my_join_field 為 Join 類型字段的名稱;relations 指定關(guān)系:question 是 answer 的父類。
例如定義一個 ID 為 1 的父文檔:
接下來定義一個子文檔,該文檔指定了父文檔 ID 為 1:
什么是 Dynamic Mapping?
Dynamic Mapping 機制使我們不需要手動定義 Mapping,ES 會自動根據(jù)文檔信息來判斷字段合適的類
型,但是有時候也會推算的不對,比如地理位置信息有可能會判斷為 Text,當(dāng)類型如果設(shè)置不對時,會
導(dǎo)致一些功能無法正常工作,比如 Range 查詢。
類型自動識別
ES 類型的自動識別是基于 JSON 的格式,如果輸入的是 JSON 是字符串且格式為日期格式,ES 會自動
設(shè)置成 Date 類型;當(dāng)輸入的字符串是數(shù)字的時候,ES 默認(rèn)會當(dāng)成字符串來處理,可以通過設(shè)置來轉(zhuǎn)換
成合適的類型;如果輸入的是 Text 字段的時候,ES 會自動增加 keyword 子字段,還有一些自動識別
下面我們通過一個例子是看看是怎么類型自動識別的,輸入如下請求,創(chuàng)建索引:
然后使用 GET /mapping_test/_mapping 查看,結(jié)果如下圖所示:
可以從結(jié)果中看出,ES 會根據(jù)文檔信息自動推算出合適的類型。
哦豁,萬一我想修改 Mapping 的字段類型,能否更改呢?讓我們分以下兩種情況來探究下:
修改 Mapping 字段類型?
如果是新增加的字段,根據(jù) Dynamic 的設(shè)置分為以下三種狀況:
當(dāng) Dynamic 設(shè)置為 true 時,一旦有新增字段的文檔寫入,Mapping 也同時被更新。
當(dāng) Dynamic 設(shè)置為 false 時,索引的 Mapping 是不會被更新的,新增字段的數(shù)據(jù)無法被索引,也就是無
法被搜索,但是信息會出現(xiàn)在 _source 中。
當(dāng) Dynamic 設(shè)置為 strict 時,文檔寫入會失敗。
另外一種是字段已經(jīng)存在,這種情況下,ES 是不允許修改字段的類型的,因為 ES 是根據(jù) Lucene 實現(xiàn)
的倒排索引,一旦生成后就不允許修改,如果希望改變字段類型,必須使用 Reindex API 重建索引。
不能修改的原因是如果修改了字段的數(shù)據(jù)類型,會導(dǎo)致已被索引的無法被搜索,但是如果是增加新的字
段,就不會有這樣的影響。
個人理解
- text和keyword
string(字符串)在es中有text
keyword
兩種類型 - 非常重要
比如address字段類型: 你又是text 又是keyword
text
是會分詞的keyword
不會分詞
在設(shè)置這個字段的時候mapping里可以指定寫入的時候用的是哪一個analyze
,查詢這個字段的時候用的是哪一個analyze
問題:我用post寫入一個不做分詞的數(shù)據(jù),為什么用match能查詢到?
寫入:寫一個有integer
keyword
text
的index
:
解析:
查詢的時候可以直接.keyword
使用term
可以完整的查詢到desc字段的數(shù)據(jù)
使用match
可以查詢到name字段的數(shù)據(jù)
使用match
能不能查詢到desc字段的數(shù)據(jù)???(能
為什么? 之前不是說過match是通過分詞來查詢的嗎? 這不就打臉了?
)
分詞規(guī)則又分為寫入時的分詞和查詢時的分詞
在寫入數(shù)據(jù)的時候你不去手動指明Analyze,es會有一定的策略來生成分詞規(guī)則
比如在進(jìn)行match查詢的時候默認(rèn)是你在寫入數(shù)據(jù)設(shè)置的規(guī)則(如果沒設(shè)置會自動生成)
這也就導(dǎo)致了match查詢的時候會優(yōu)先使用指定的,如果沒指定 會使用創(chuàng)建mapping的時候的策略
4. Elasticsearch Analyze(重點):
Elasticsearch 中文本分析Analysis是把全文本轉(zhuǎn)換成一系列的單詞(term/token)的過程,也叫分詞。文
本分析是使用分析器 Analyzer 來實現(xiàn)的,Elasticsearch內(nèi)置了分析器,用戶也可以按照自己的需求自定
義分析器。
為了提高搜索準(zhǔn)確性,除了在數(shù)據(jù)寫入時轉(zhuǎn)換詞條,匹配 Query 語句時候也需要用相同的分析器對查詢
語句進(jìn)行分析。
Analyzer 的組成
Analyzer 由三部分組成:Character Filters
、Tokenizer
、Token Filters
Character Filters
Character Filters字符過濾器接收原始文本text的字符流,可以對原始文本增加、刪除字段或者對字符做
轉(zhuǎn)換。一個Analyzer 分析器可以有 0-n 個按順序執(zhí)行的字符過濾器。
Tokenizer
Tokenizer 分詞器接收Character Filters輸出的字符流,將字符流分解成的那個的單詞,并且輸出單詞流。
例如空格分詞器會將文本按照空格分解,將 “Quick brown fox!” 轉(zhuǎn)換成 [Quick, brown, fox!]。分詞器也負(fù)
責(zé)記錄每個單詞的順序和該單詞在原始文本中的起始和結(jié)束偏移 offsets 。
一個Analyzer 分析器有且只有 1個分詞器。
Token Filters
Token Filter單詞過濾器接收分詞器Tokenizer輸出的單詞流,可以對單詞流中的單詞做添加、移除或者轉(zhuǎn)換操作,例如lowercase token filter會將單詞全部轉(zhuǎn)換成小寫,stop token filter會移除the、and這種通用單詞, synonym token filter會往單詞流中添加單詞的同義詞。
Token filters不允許改變單詞在原文檔的位置以及起始、結(jié)束偏移量。
一個Analyzer分析器可以有O-n 個按順序執(zhí)行的單詞過濾器。
Elasticsearch內(nèi)置分詞器
Standard Analyzer - 默認(rèn)分詞器,按詞切分,小寫處理
Simple Analyzer - 按照非字母切分(符號被過濾),小寫處理
Stop Analyzer - 小寫處理,停用詞過濾(the ,a,is)
Whitespace Analyzer - 按照空格切分,不轉(zhuǎn)小寫
Keyword Analyzer - 不分詞,直接將輸入當(dāng)做輸出
Patter Analyzer - 正則表達(dá)式,默認(rèn) \W+
Language - 提供了 30 多種常見語言的分詞器
Standard Analyzer
- 默認(rèn)分詞器
- 按詞分類
- 小寫處理
#standard
GET _analyze
{
"analyzer": "standard",
"text": "The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."
}
輸出:
[the,2,quick,brown,foxes,a,jumped,over,the,lazy,dog’s,bone]
Simple Analyzer
- 按照非字母切分,非字母則會被去除
- 小寫處理
#simpe
GET _analyze
{
"analyzer": "simple",
"text": "The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."
}
輸出:
[the,quick,brown,foxes,jumped,over,the,lazy,dog,s,bone]
Stop Analyzer
- 小寫處理
- 停用詞過濾(the,a, is)
GET _analyze
{
"analyzer": "stop",
"text": "The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."
}
輸出:
[quick,brown,foxes,jumped,over,lazy,dog,s,bone]
Whitespace Analyzer
- 按空格切分
#stop
GET _analyze
{
"analyzer": "whitespace",
"text": "The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."
}
輸出:
[The,2,QUICK,Brown-Foxes,jumped,over,the,lazy,dog’s,bone.]
Keyword Analyzer
- 不分詞,當(dāng)成一整個 term 輸出
#keyword
GET _analyze
{
"analyzer": "keyword",
"text": "The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."
}
輸出:
[The 2 QUICK Brown-Foxes jumped over the lazy dog’s bone.]
Patter Analyzer
- 通過正則表達(dá)式進(jìn)行分詞
- 默認(rèn)是 \W+(非字母進(jìn)行分隔)
GET _analyze
{
"analyzer": "pattern",
"text": "The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."
}
輸出:
[the,2,quick,brown,foxes,jumped,over,the,lazy,dog,s,bone]
Language Analyzer
支持語言:arabic, armenian, basque, bengali, bulgarian, catalan, czech, dutch, english, finnish, french,galician, german, hindi, hungarian, indonesian, irish, italian, latvian, lithuanian, norwegian, portuguese,romanian, russian, sorani, spanish, swedish, turkish.
#english
GET _analyze
{
"analyzer": "english",
"text": "The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."
}
輸出:
[2,quick,brown,fox,jump,over,the,lazy,dog,bone]
中文分詞要比英文分詞難,英文都以空格分隔,中文理解通常需要上下文理解才能有正確的理解,比如
[蘋果,不大好吃]和
[蘋果,不大,好吃],這兩句意思就不一樣。
常用的插件分詞器
IK Analyzer - 對中文分詞友好,支持遠(yuǎn)程詞典熱更新,有ik_smart 、ik_max_word 兩種分析器
pinyin Analyzer - 可以對中文進(jìn)行拼音分析,搜索時使用拼音即可搜索出來對應(yīng)中文
ICU Analyzer - 提供了 Unicode 的支持,更好的支持亞洲語言
hanLP Analyzer - 基于NLP的中文分析器
十一、分詞的重要性
文本分詞
單詞是語言中重要的基本元素。一個單詞可以代表一個信息單元,有著指代名稱、功能、動作、性質(zhì)等作用。在語言的進(jìn)化史中,不斷有新的單詞涌現(xiàn),也有許多單詞隨著時代的變遷而邊緣化直至消失。根據(jù)統(tǒng)計,《漢語詞典》中包含的漢語單詞數(shù)目在37萬左右,《牛津英語詞典》中的詞匯約有17萬。
理解單詞對于分析語言結(jié)構(gòu)和語義具有重要的作用。因此,在機器閱讀理解算法中,模型通常需要首先對語句和文本進(jìn)行單詞分拆和解析。
分詞(tokenization)的任務(wù)是將文本以單詞為基本單元進(jìn)行劃分。由于許多詞語存在詞型的重疊,以及
組合詞的運用,解決歧義性是分詞任務(wù)中的一個挑戰(zhàn)。不同的分拆方式可能表示完全不同的語義。如在以下例子中,兩種分拆方式代表的語義都有可能:
南京市|?江|?橋
南京|市?|江?橋
分詞的意義 - nlp
-
將復(fù)雜問題轉(zhuǎn)化為數(shù)學(xué)問題
在 機器學(xué)習(xí)的文章 中講過,機器學(xué)習(xí)之所以看上去可以解決很多復(fù)雜的問題,是因為它把這些問題都轉(zhuǎn)化為了數(shù)學(xué)問題。
而 NLP 也是相同的思路,文本都是一些「非結(jié)構(gòu)化數(shù)據(jù)」,我們需要先將這些數(shù)據(jù)轉(zhuǎn)化為「結(jié)構(gòu)化數(shù)
據(jù)」,結(jié)構(gòu)化數(shù)據(jù)就可以轉(zhuǎn)化為數(shù)學(xué)問題了,而分詞就是轉(zhuǎn)化的第一步。 -
詞是一個比較合適的粒度
詞是表達(dá)完整含義的最小單位。
字的粒度太小,無法表達(dá)完整含義,比如”鼠“可以是”老鼠“,也可以是”鼠標(biāo)“。
而句子的粒度太大,承載的信息量多,很難復(fù)用。比如”傳統(tǒng)方法要分詞,一個重要原因是傳統(tǒng)方法對遠(yuǎn)距離依賴的建模能力較弱?!?/p>
中英文分詞的3個典型區(qū)別
區(qū)別1:分詞方式不同,中文更難
英文有天然的空格作為分隔符,但是中文沒有。所以如何切分是一個難點,再加上中文里一詞多意的情況非常多,導(dǎo)致很容易出現(xiàn)歧義。下文中難點部分會詳細(xì)說明。
區(qū)別2:英文單詞有多種形態(tài)
英文單詞存在豐富的變形變換。為了應(yīng)對這些復(fù)雜的變換,英文NLP相比中文存在一些獨特的處理步驟,我們稱為詞形還原(Lemmatization)和詞干提?。⊿temming)。中文則不需要
詞性還原:does,done,doing,did 需要通過詞性還原恢復(fù)成 do。
詞干提?。篶ities,children,teeth 這些詞,需要轉(zhuǎn)換為 city,child,tooth”這些基本形態(tài)
區(qū)別3:中文分詞需要考慮粒度問題
例如「中國科學(xué)技術(shù)大學(xué)」就有很多種分法:
- 中國科學(xué)技術(shù)大學(xué)
- 中國 \ 科學(xué)技術(shù) \ 大學(xué)
- 中國 \ 科學(xué) \ 技術(shù) \ 大學(xué)
粒度越大,表達(dá)的意思就越準(zhǔn)確,但是也會導(dǎo)致召回比較少。所以中文需要不同的場景和要求選擇不同的粒度。這個在英文中是沒有的。
中文分詞的3大難點
難點 1:沒有統(tǒng)一的標(biāo)準(zhǔn)
目前中文分詞沒有統(tǒng)一的標(biāo)準(zhǔn),也沒有公認(rèn)的規(guī)范。不同的公司和組織各有各的方法和規(guī)則。
難點 2:歧義詞如何切分
例如「兵乓球拍賣完了」就有2種分詞方式表達(dá)了2種不同的含義:
- 乒乓球 \ 拍賣 \ 完了
- 乒乓 \ 球拍 \ 賣 \ 完了
難點 3:新詞的識別
信息爆炸的時代,三天兩頭就會冒出來一堆新詞,如何快速的識別出這些新詞是一大難點。比如當(dāng)年「藍(lán)瘦香菇」大火,就需要快速識別。
3種典型的分詞方法
分詞的方法大致分為 3 類:
- 基于詞典匹配
- 基于統(tǒng)計
- 基于深度學(xué)習(xí)
給予詞典匹配的分詞方式
優(yōu)點:速度快、成本低
缺點:適應(yīng)性不強,不同領(lǐng)域效果差異大
基本思想是基于詞典匹配,將待分詞的中文文本根據(jù)一定規(guī)則切分和調(diào)整,然后跟詞典中的詞語進(jìn)行匹
配,匹配成功則按照詞典的詞分詞,匹配失敗通過調(diào)整或者重新選擇,如此反復(fù)循環(huán)即可。代表方法有基于正向最大匹配和基于逆向最大匹配及雙向匹配法。
基于統(tǒng)計的分詞方法
優(yōu)點:適應(yīng)性較強
缺點:成本較高,速度較慢
這類目前常用的是算法是 **HMM、CRF、SVM、深度學(xué)習(xí) **等算法,比如stanford、Hanlp分詞工具是基于CRF算法。以CRF為例,基本思路是對漢字進(jìn)行標(biāo)注訓(xùn)練,不僅考慮了詞語出現(xiàn)的頻率,還考慮上下文,具備較好的學(xué)習(xí)能力,因此其對歧義詞和未登錄詞的識別都具有良好的效果。
基于深度學(xué)習(xí)
優(yōu)點:準(zhǔn)確率高、適應(yīng)性強
缺點:成本高,速度慢
例如有人員嘗試使用雙向LSTM+CRF實現(xiàn)分詞器,其本質(zhì)上是序列標(biāo)注,所以有通用性,命名實體識別
等都可以使用該模型,據(jù)報道其分詞器字符準(zhǔn)確率可高達(dá)97.5%。
常見的分詞器都是使用機器學(xué)習(xí)算法和詞典相結(jié)合,一方面能夠提高分詞準(zhǔn)確率,另一方面能夠改善領(lǐng)域適應(yīng)性。
中文分詞工具
下面排名根據(jù) GitHub 上的 star 數(shù)排名:
- jieba
- Hanlp
- IK
- Stanford 分詞
- ansj 分詞器
- 哈工大 LTP
- KCWS分詞器
- 清華大學(xué)THULAC
- ICTCLAS
英文分詞工具
- Keras
- Spacy
- Gensim
- NLTK
總結(jié)
分詞就是將句子、段落、文章這種長文本,分解為以字詞為單位的數(shù)據(jù)結(jié)構(gòu),方便后續(xù)的處理分析工作。
分詞的原因:
- 將復(fù)雜問題轉(zhuǎn)化為數(shù)學(xué)問題
- 詞是一個比較合適的粒度
- 深度學(xué)習(xí)時代,部分任務(wù)中也可以「分字」
中英文分詞的3個典型區(qū)別:
- 分詞方式不同,中文更難
- 英文單詞有多種形態(tài),需要詞性還原和詞干提取
- 中文分詞需要考慮粒度問題
中文分詞的3大難點
- 沒有統(tǒng)一的標(biāo)準(zhǔn)
- 歧義詞如何切分
- 新詞的識別
3個典型的分詞方式:
- 基于詞典匹配
- 基于統(tǒng)計
- 基于深度學(xué)習(xí)
十二、ik分詞器的安裝和配置
1.下載
下載的版本一定要和es的版本保持一致 查看es版本訪問ip:9200
下載地址
2.解壓拷貝到plugins目錄下
之前用docker安裝的時候掛載了plugins 直接解壓到里面就行
將目錄文件夾改名為ik - 必須改名
進(jìn)入容器后在bin
目錄下執(zhí)行./elasticsearch-plugin list
可以查看安裝過哪些插件
3. 設(shè)置權(quán)限
cd /data/elasticsearch/plugins
chmod 777 -R ik
4. docker restart 重啟容器
5. 分詞器使用
ik_smart
和 ik_max_word
ik_max_word:將分詞的可能全部列舉出來
ik_smart就普通分詞:
可以改mappings
里的analyzer
注意 如果這個字段已經(jīng)存在的話是沒辦法修改mappings里的analyzer 因為它在初始化的時候已經(jīng)分詞了 新增一個index即可
查詢一下:
它是基于詞庫來分詞的
6.自定義詞庫
中文中有很多專用名詞 他的詞庫里就沒有這些名詞 我們得自定義
很多時候也得解決停用詞的問題 比如上述的**“的”、“是”、“不”**等等這樣的詞
就得擴展詞庫 和 擴展停用詞庫
自定義庫得到ik
的目錄下config
添加.dic
文件
cd到ik下的config目錄
vim添加一個.dic結(jié)尾的文件 比如我添加一個擴展詞庫和一個停用詞庫 詳細(xì)如下:
mydic.dic內(nèi)容:
慕課網(wǎng)
中華牙膏
extra_stopword.dic內(nèi)容:
的
是
喲
定義完之后開始配置
回到上級目錄編輯IKAnalyzer.cfg.xml
然后重啟docker
再查詢一下看看效果:
詞庫已分詞 停用詞已屏蔽 ok文章來源:http://www.zghlxwxcb.cn/news/detail-770589.html
在查詢的時候如果不想指明analyze
就配置mapping
文章來源地址http://www.zghlxwxcb.cn/news/detail-770589.html
PUT newCN
{
"mappings": {
"properties": {
"name":{
"type": "text",
"analyzer": "ik_smart",
"search_analyzer": "ik_smart"
}
}
}
}
到了這里,關(guān)于【搜索引擎】elasticsearch入門到進(jìn)階 - 常用接口的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!