Elasticsearch 是一個(gè)分布式的般甲、可擴(kuò)展的、近實(shí)時(shí)的開源搜索分析引擎鹅颊。它支持 PB 級(jí)的容量敷存,在存儲(chǔ)時(shí)通過對(duì)文檔的分析和建立索引,使之可以被全文搜索堪伍、分析锚烦。它的底層基于開源庫(kù) Luceue 。Elasticsearch 對(duì) Luceue 進(jìn)行了封裝并提供了 REST API 的操作接口杠娱,開箱即用挽牢。
基本概念
概念對(duì)比
學(xué)習(xí)新內(nèi)容時(shí),最容易的理解方式是用它和已經(jīng)熟悉的概念進(jìn)行比較摊求。下面是 Elasticsearch 與 Mysql 對(duì)應(yīng)概念的比較禽拔。
概念 | Mysql | Elasticsearch |
---|---|---|
Index 索引 | 數(shù)據(jù)庫(kù) | 一個(gè)邏輯上存儲(chǔ)文檔的地方,可以是集群 |
Type 類型 | 數(shù)據(jù)表 | 一個(gè)索引可以在邏輯上分為不同的類型室叉。與 Mysql 不同之處在于一個(gè)索引中的不同類型的字段是相同的睹栖;而數(shù)據(jù)庫(kù)中不同表的字段基本上是不同的。 |
Document 文檔 | 數(shù)據(jù)行 | 一個(gè)文檔對(duì)象所有的鍵和值茧痕,是 JSON 格式野来,比 Mysql 復(fù)雜,可以包含對(duì)象踪旷、數(shù)組 |
Mapping 映射 | 數(shù)據(jù)類型 | 除了描述文檔中每個(gè)值的數(shù)據(jù)類型曼氛,還包括字段的 index(怎樣索引字符串) , analyzer(指定搜索和索引時(shí)使用的分析器) |
shard 主分片 | 無(wú) | 一個(gè)分片是一個(gè) Lucene 索引令野。一個(gè) ES 索引的分片數(shù)是在創(chuàng)建索引的時(shí)候設(shè)置的舀患,因?yàn)橛辛朔制珽S 水平擴(kuò)展時(shí)變得容易 |
replica 副本分片 | 類似從庫(kù) | ES 的副本分片可以在創(chuàng)建時(shí)設(shè)置气破,在創(chuàng)建后修改 |
一個(gè) Elasticsearch 服務(wù)的實(shí)例為一個(gè)節(jié)點(diǎn)聊浅,一個(gè)節(jié)點(diǎn)可以包含多個(gè)分片,至少需要包含一個(gè)分片现使。
Elasticsearch 的存儲(chǔ)容量大小為所有的主分片容量決定低匙。所以在創(chuàng)建索引的時(shí)候需要考慮分片預(yù)分配。默認(rèn)為 5 個(gè)主分片碳锈,也就是最后水平可擴(kuò)展最大的容量為 5 個(gè) ES 服務(wù)實(shí)例顽冶。
對(duì)比例子
下面是使用 Mysql 創(chuàng)建一個(gè)雇員數(shù)據(jù)庫(kù)和使用 Elasticsearch 創(chuàng)建一個(gè)雇員索引的比較。
雇員屬性有:first_name售碳、last_name渗稍、age佩迟、about (簡(jiǎn)介)
使用 Mysql 創(chuàng)建
- 創(chuàng)建數(shù)據(jù)庫(kù) megacorp 。
- 創(chuàng)建表 employee 竿屹,定義表的字段。設(shè)置字段的長(zhǎng)度灸姊、類型拱燃,根據(jù)需要設(shè)置表的索引。
- 插入數(shù)據(jù)力惯。
使用 Elasticsearch 創(chuàng)建
- 創(chuàng)建索引碗誉,創(chuàng)建時(shí)確定索引的分片數(shù)、副本分片數(shù)父晶。如果不指定哮缺, ES 默認(rèn) 5 分片、1 副本分片甲喝。
- 設(shè)置索引的 Mapping 尝苇。 比如 about 用 text 類型存儲(chǔ),age 用 long 類型埠胖。about 需要使用 ik-analyzer 中文分詞器糠溜,這樣就可以通過簡(jiǎn)介的內(nèi)容搜索對(duì)應(yīng)的雇員;而 age 設(shè)置為 not_analyzed (建立索引的時(shí)候直撤,直接對(duì) age 字段值建立索引非竿,不會(huì)對(duì)內(nèi)容進(jìn)行分析,基本類型默認(rèn) date谋竖、long 默認(rèn)為 not_analyzed)红柱。
- 索引雇員文檔到 Elasticsearch 中。
默認(rèn)情況下蓖乘,文檔中每一個(gè)屬性都會(huì)被索引锤悄,沒有索引的屬性是不能被搜索的。
Elasticsearch 集群搭建
使用 Docker-compose 可以讓搭建 Elasticsearch 變得更簡(jiǎn)單驱敲。
集群文件目錄如下:
docker-compose.yml 文檔內(nèi)容
version: '2.2'
services:
elasticsearch:
image: elasticsearch:6.5.1
container_name: es
environment:
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- ./es1/data:/usr/share/elasticsearch/data
- ./es1/es.yml:/usr/share/elasticsearch/config/elasticsearch.yml
ports:
- 9200:9200
- 9300:9300
networks:
- esnet
elasticsearch2:
image: elasticsearch:6.5.1
container_name: es2
environment:
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- ./es2/data:/usr/share/elasticsearch/data
- ./es2/es.yml:/usr/share/elasticsearch/config/elasticsearch.yml
networks:
- esnet
elasticsearch3:
image: elasticsearch:6.5.1
container_name: es3
environment:
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- ./es3/data:/usr/share/elasticsearch/data
- ./es3/es.yml:/usr/share/elasticsearch/config/elasticsearch.yml
networks:
- esnet
networks:
esnet:
ES_JAVA_OPTS 設(shè)置 ES 使用的最大與最小 heap 空間铁蹈。
主節(jié)點(diǎn) es.yml
cluster.name: es-cluster
bootstrap.memory_lock: true
node.name: node-master
node.master: true
node.data: true
network.host: 0.0.0.0
http.port: 9200
transport.tcp.port: 9300
network.publish_host: es
transport.tcp.compress: true
discovery.zen.ping.unicast.hosts: ["es:9300", "es1:9300", "es3:9300"]
cluster.name 為 ES 集群名稱,集群所有的節(jié)點(diǎn)必須是相同的名稱众眨。
bootstrap.memory_lock 用于鎖定 ES 進(jìn)程使用的內(nèi)存地址握牧,防止被 swap out
node.name 為節(jié)點(diǎn)的名稱
node.master 是否為主節(jié)點(diǎn)
node.data 節(jié)點(diǎn)是否存儲(chǔ)數(shù)據(jù)
http.port 為外部訪問 ES 服務(wù)的端口
transport.tcp.port 為 ES 集群通信的端口
transport.tcp.compress 集群通信時(shí)進(jìn)行壓縮
discovery.zen.ping.unicast.hosts 單播發(fā)現(xiàn)。 ES 將在這里面的地址去通信發(fā)現(xiàn)集群節(jié)點(diǎn)
工作節(jié)點(diǎn) es.yml
cluster.name: es-cluster
bootstrap.memory_lock: true
node.name: node-master-3
node.master: false
node.data: true
network.host: 0.0.0.0
http.port: 9200
transport.tcp.port: 9300
network.publish_host: es3
discovery.zen.ping.unicast.hosts: ["es:9300", "es2:9300", "es3:9300"]
工作節(jié)點(diǎn)與主節(jié)點(diǎn)主要是 node.master 的配置不同
docker-compose up
這樣一個(gè)主節(jié)點(diǎn)娩梨、2個(gè)工作節(jié)點(diǎn)的 Elasticsearch 集群就搭建起來(lái)了沿腰。
結(jié)構(gòu)化搜索實(shí)踐
一個(gè) Elasticsearch 的查詢包含:
- 查詢內(nèi)容所在的索引、類型狈定。 多個(gè)索引颂龙、多個(gè)類型之間使用“,”分割习蓬。
- 路由 routing 。如果數(shù)據(jù)建立索引的時(shí)候有指定路由措嵌,查詢的時(shí)候可以指定路由躲叼,這樣 ES 就不用到每個(gè)分片去查詢一次了。
- 查詢語(yǔ)句 query 企巢。
- 排序枫慷。根據(jù)指定字段、排序方式進(jìn)行排序浪规。
- 分頁(yè)或听。可以通過 from笋婿、limit 查詢指定的數(shù)據(jù)誉裆。
一個(gè)簡(jiǎn)單的 DSL SQL
curl -X GET "localhost:9200/bank/account/_search" -d '
{
"query" : {
"match": {
"title" : "search"
}
},
"from": 10,
"size": 10,
"sort": [
{"date": {"order":"asc"}}
]
}'
bank 為查詢的索引; account 為查詢的類型缸濒;query 中為查詢語(yǔ)句足丢。
Elasticsearch 中的查詢分為簡(jiǎn)單查詢、組合查詢绍填。
常用的簡(jiǎn)單查詢又分為了查詢(query context)霎桅、過濾(filter context)。查詢時(shí)不僅要找到匹配對(duì)應(yīng)內(nèi)容的文檔讨永,還會(huì)計(jì)算文檔的分?jǐn)?shù)(score), 過濾只需找到對(duì)應(yīng)的文檔滔驶,而不計(jì)算文檔的分?jǐn)?shù)。官方推薦能用過濾的地方就不要用查詢卿闹。
簡(jiǎn)單查詢
- match_all 和 match_none
查詢所有的內(nèi)容
curl -X GET "localhost:9200/bank/_search" -d '
{
"query" : {
"match_all": {}
}
}'
- 全文索引
a. match 指定的分析器先對(duì)查詢內(nèi)容進(jìn)行分析揭糕,然后對(duì)分析的內(nèi)容在倒排索引中進(jìn)行查詢; match_phrase 也會(huì)先將搜索內(nèi)容分析為詞項(xiàng)锻霎,然后對(duì)詞項(xiàng)進(jìn)行搜索著角,但是匹配的數(shù)據(jù)需要包含所有的詞項(xiàng)。
curl -X GET "localhost:9200/bank/account/_search" -d '
{
"query" : {
"match": {"title":"search"}
}
}'
b. multi_match 通過對(duì)多個(gè)字段進(jìn)行 match 搜索
curl -X GET "localhost:9200/bank/_search" -d '
{
"query" : {
"multi_match": {
"query":"this is test",
"fields": ["title", "subtitle"]
}
}
}'
c. query_string 通過查詢語(yǔ)句進(jìn)行查詢
new york city 和 big apple 是兩個(gè)獨(dú)立的查詢內(nèi)容
curl -X GET "localhost:9200/bank/_search" -d '
{
"query" : {
"query_string": {
"query":"(new york city) OR (big apple)",
"default_field": ["subtitle"]
}
}
}'
- Term 查詢
全文查詢?cè)诓樵兦皶?huì)將查詢內(nèi)容分析為詞項(xiàng)旋恼,然后進(jìn)行查詢吏口; term 查詢不對(duì)查詢內(nèi)容進(jìn)行分析,是對(duì)值進(jìn)行精確的查詢冰更。Term 查詢不會(huì)計(jì)算查詢結(jié)果的分?jǐn)?shù)(score)产徊,屬于過濾查詢(filter context)。
a. term 和 terms
對(duì)指定的一個(gè)和多個(gè)內(nèi)容進(jìn)行精確查詢
curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
"query": {
"terms" : { "user" : ["kimchy", "elasticsearch"]}
}
}
'
b. range 查詢
文檔屬性值在一個(gè)范圍的查詢蜀细≈弁可以是字符串、數(shù)字奠衔、日期谆刨。
curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
"query": {
"range" : {
"age" : {
"gte" : 10,
"lte" : 20
}
}
}
}'
c. exists 查詢
查找指定屬性至少又一個(gè)非空值的文檔塘娶。
curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
"query": {
"exists" : { "field" : "user" }
}
}'
d. wildcard 查詢
根據(jù)通配符進(jìn)行查詢(? 匹配1個(gè)任意字符;* 匹配多個(gè)任意字符)痊夭。查詢會(huì)耗性能刁岸。
curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
"query": {
"wildcard" : { "user" : "ki*y" }
}
}'
復(fù)合查詢
將多個(gè)簡(jiǎn)單查詢通過組合起來(lái)就是一個(gè)復(fù)合查詢了。常用的組合方式有下面幾種生兆。
- constant_score难捌。這個(gè)查詢里面的查詢將不再計(jì)算分?jǐn)?shù),統(tǒng)一返回指定的分?jǐn)?shù)鸦难。
curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
"query": {
"constant_score" : {
"filter" : {
"term" : { "user" : "kimchy"}
},
"boost" : 2
}
}
}'
查詢結(jié)果所有文檔的 _score 都為 2 。
- bool
邏輯組合员淫,包括 must合蔽、should、must_not介返、filter拴事。must 和 should 的查詢會(huì)計(jì)算分?jǐn)?shù),其他的不會(huì)圣蝎。
must 必須包含刃宵; should 單獨(dú)查詢的時(shí)候,至少需要滿足一個(gè)條件徘公,與 must牲证、filter 組合的時(shí)候可以不需要滿足。