簡介
Elasticsearch
是一個高度可擴展的開源的分佈式Restful
全文搜索和分析引擎。它允許用戶快速的(近實時的)存儲、搜索和分析海量數據。它通常用作底層引擎技術,爲具有複雜搜索功能和要求的應用程序提供支持。 以下是ES
可用於的一些場景:
- 電商網站提供搜索功能:可使用
ES
來存儲產品的目錄和庫存,併爲它們提供搜索和自動填充建議。 - 收集日誌和交易數據,並進行分析:可使用
Logstash
來收集、聚合和解析數據, 然後讓Logstash
將此數據提供給ES
。然後可在ES
中搜索和聚合開發者感興趣的信息。 - 需要快速調查、分析、可視化查詢大量數據的特定問題:可以使用ES存儲數據,然後使用
Kibana
構建自定義儀表板,來可視化展示數據。還可以使用ES的聚合功能針對這些數據進行復雜的商業分析。
我們要認識一個人Doug Cutting
爲什麼要提Doug Cutting
,因爲Elasticsearch的底層是Lucene,而Lucene就是Doug Cutting
大神寫的。
引用來自於: 鮮棗課堂
1998年9月4日,Google公司在美國硅谷成立。正如大家所知,它是一家做搜索引擎起家的公司。
無獨有偶,一位名叫Doug Cutting的美國工程師,也迷上了搜索引擎。他做了一個用於文本搜索的函數庫(姑且理解爲軟件的功能組件),命名爲Lucene。
左爲Doug Cutting,右爲Lucene的LOGO
Lucene是用JAVA寫成的,目標是爲各種中小型應用軟件加入全文檢索功能。因爲好用而且開源(代碼公開),非常受程序員們的歡迎。
早期的時候,這個項目被髮布在Doug Cutting的個人網站和SourceForge(一個開源軟件網站)。後來,2001年底,Lucene成爲Apache軟件基金會jakarta項目的一個子項目。
Apache軟件基金會,搞IT的應該都認識
2004年,Doug Cutting再接再勵,在Lucene的基礎上,和Apache開源夥伴Mike Cafarella合作,開發了一款可以代替當時的主流搜索的開源搜索引擎,命名爲Nutch。
Nutch是一個建立在Lucene核心之上的網頁搜索應用程序,可以下載下來直接使用。它在Lucene的基礎上加了網絡爬蟲和一些網頁相關的功能,目的就是從一個簡單的站內檢索推廣到全球網絡的搜索上,就像Google一樣。
Nutch在業界的影響力比Lucene更大。
大批網站採用了Nutch平臺,大大降低了技術門檻,使低成本的普通計算機取代高價的Web服務器成爲可能。甚至有一段時間,在硅谷有了一股用Nutch低成本創業的潮流。
隨着時間的推移,無論是Google還是Nutch,都面臨搜索對象“體積”不斷增大的問題。
尤其是Google,作爲互聯網搜索引擎,需要存儲大量的網頁,並不斷優化自己的搜索算法,提升搜索效率。
Google搜索欄
在這個過程中,Google確實找到了不少好辦法,並且無私地分享了出來。
2003年,Google發表了一篇技術學術論文,公開介紹了自己的谷歌文件系統GFS(Google File System)。這是Google公司爲了存儲海量搜索數據而設計的專用文件系統。
第二年,也就是2004年,Doug Cutting基於Google的GFS論文,實現了分佈式文件存儲系統,並將它命名爲NDFS(Nutch Distributed File System)。
還是2004年,Google又發表了一篇技術學術論文,介紹自己的MapReduce編程模型。這個編程模型,用於大規模數據集(大於1TB)的並行分析運算。
第二年(2005年),Doug Cutting又基於MapReduce,在Nutch搜索引擎實現了該功能。
2006年,當時依然很厲害的Yahoo(雅虎)公司,招安了Doug Cutting。
這裏要補充說明一下雅虎招安Doug的背景:2004年之前,作爲互聯網開拓者的雅虎,是使用Google搜索引擎作爲自家搜索服務的。在2004年開始,雅虎放棄了Google,開始自己研發搜索引擎。所以。。。
加盟Yahoo之後,Doug Cutting將NDFS和MapReduce進行了升級改造,並重新命名爲Hadoop(NDFS也改名爲HDFS,Hadoop Distributed File System)。
這個,就是後來大名鼎鼎的大數據框架系統——Hadoop的由來。而Doug Cutting,則被人們稱爲Hadoop之父。
Hadoop這個名字,實際上是Doug Cutting他兒子的黃色玩具大象的名字。所以,Hadoop的Logo,就是一隻奔跑的黃色大象。
我們繼續往下說。
還是2006年,Google又發論文了。
這次,它們介紹了自己的BigTable。這是一種分佈式數據存儲系統,一種用來處理海量數據的非關係型數據庫。
Doug Cutting當然沒有放過,在自己的hadoop系統裏面,引入了BigTable,並命名爲HBase。
好吧,反正就是緊跟Google時代步伐,你出什麼,我學什麼。
所以,Hadoop的核心部分,基本上都有Google的影子。
其實從這裏也能看到,站在巨人肩膀上或者仿照強者,也可以走出一條屬於自己的道路。
安裝Elasticsearch
➜ Tools brew search elasticsearch
==> Formulae
elasticsearch [email protected] [email protected]
➜ Tools brew install [email protected]
==> Downloading https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.6.16.tar.gz
######################################################################## 100.0%
Warning: [email protected] has been deprecated!
==> Caveats
Data: /usr/local/var/elasticsearch/elasticsearch_chenyuan/
Logs: /usr/local/var/log/elasticsearch/elasticsearch_chenyuan.log
Plugins: /usr/local/opt/[email protected]/libexec/plugins/
Config: /usr/local/etc/elasticsearch/
plugin script: /usr/local/opt/[email protected]/libexec/bin/elasticsearch-plugin
[email protected] is keg-only, which means it was not symlinked into /usr/local,
because this is an alternate version of another formula.
If you need to have [email protected] first in your PATH run:
echo 'export PATH="/usr/local/opt/[email protected]/bin:$PATH"' >> ~/.zshrc
To have launchd start [email protected] now and restart at login:
brew services start [email protected]
Or, if you don't want/need a background service you can just run:
/usr/local/opt/[email protected]/bin/elasticsearch
==> Summary
/usr/local/Cellar/[email protected]/5.6.16: 106 files, 36.0MB, built in 10 seconds
==> `brew cleanup` has not been run in 30 days, running now...
Removing: /Users/chenyuan/Library/Caches/Homebrew/erlang--22.1.2.mojave.bottle.tar.gz... (77.3MB)
Removing: /Users/chenyuan/Library/Caches/Homebrew/gettext--0.20.1.catalina.bottle.tar.gz... (8.3MB)
Removing: /Users/chenyuan/Library/Caches/Homebrew/icu4c--64.2.catalina.bottle.tar.gz... (26.1MB)
Removing: /Users/chenyuan/Library/Caches/Homebrew/jpeg--9c.mojave.bottle.tar.gz... (300.8KB)
Removing: /Users/chenyuan/Library/Caches/Homebrew/libpng--1.6.37.mojave.bottle.tar.gz... (442.2KB)
Removing: /Users/chenyuan/Library/Caches/Homebrew/libtiff--4.0.10_1.mojave.bottle.tar.gz... (1MB)
Removing: /Users/chenyuan/Library/Caches/Homebrew/node--12.11.1.catalina.bottle.tar.gz... (14.8MB)
Removing: /Users/chenyuan/Library/Caches/Homebrew/[email protected]... (5.2MB)
Removing: /Users/chenyuan/Library/Caches/Homebrew/perl--5.30.0.catalina.bottle.tar.gz... (16.3MB)
Removing: /Users/chenyuan/Library/Caches/Homebrew/rabbitmq--3.8.0.tar.xz... (11MB)
Removing: /Users/chenyuan/Library/Caches/Homebrew/subversion--1.12.2_1.catalina.bottle.1.tar.gz... (10MB)
Removing: /Users/chenyuan/Library/Caches/Homebrew/utf8proc--2.4.0.catalina.bottle.tar.gz... (152.2KB)
Removing: /Users/chenyuan/Library/Caches/Homebrew/wxmac--3.0.4_2.mojave.bottle.tar.gz... (7.4MB)
Removing: /Users/chenyuan/Library/Logs/Homebrew/icu4c... (64B)
Removing: /Users/chenyuan/Library/Logs/Homebrew/node... (64B)
Pruned 0 symbolic links and 2 directories from /usr/local
查看一下版本號,結果沒有結果。
➜ ~ elasticsearch --version
zsh: command not found: elasticsearch
然後看之前的日誌,需要你手動配置一下環境變量。
echo 'export PATH="/usr/local/opt/[email protected]/bin:$PATH"' >> ~/.zshrc
# 重新加載環境變量
➜ ~ source ~/.zshrc
➜ ~ elasticsearch --version
Version: 5.6.16, Build: 3a740d1/2019-03-13T15:33:36.565Z, JVM: 1.8.0_162
啓動ElasticSearch
➜ ~ elasticsearch
[2020-05-14T21:47:06,301][INFO ][o.e.n.Node ] [] initializing ...
[2020-05-14T21:47:06,403][INFO ][o.e.e.NodeEnvironment ] [vXW29Yn] using [1] data paths, mounts [[/ (/dev/disk1s5)]], net usable_space [42.5gb], net total_space [465.7gb], spins? [unknown], types [apfs]
[2020-05-14T21:47:06,404][INFO ][o.e.e.NodeEnvironment ] [vXW29Yn] heap size [1.9gb], compressed ordinary object pointers [true]
[2020-05-14T21:47:06,406][INFO ][o.e.n.Node ] node name [vXW29Yn] derived from node ID [vXW29YnkRDaIb8XuGeKRxQ]; set [node.name] to override
[2020-05-14T21:47:06,406][INFO ][o.e.n.Node ] version[5.6.16], pid[75858], build[3a740d1/2019-03-13T15:33:36.565Z], OS[Mac OS X/10.15.4/x86_64], JVM[Oracle Corporation/Java HotSpot(TM) 64-Bit Server VM/1.8.0_162/25.162-b12]
[2020-05-14T21:47:06,406][INFO ][o.e.n.Node ] JVM arguments [-Xms2g, -Xmx2g, -XX:+UseConcMarkSweepGC, -XX:CMSInitiatingOccupancyFraction=75, -XX:+UseCMSInitiatingOccupancyOnly, -XX:+AlwaysPreTouch, -Xss1m, -Djava.awt.headless=true, -Dfile.encoding=UTF-8, -Djna.nosys=true, -Djdk.io.permissionsUseCanonicalPath=true, -Dio.netty.noUnsafe=true, -Dio.netty.noKeySetOptimization=true, -Dio.netty.recycler.maxCapacityPerThread=0, -Dlog4j.shutdownHookEnabled=false, -Dlog4j2.disable.jmx=true, -Dlog4j.skipJansi=true, -XX:+HeapDumpOnOutOfMemoryError, -Des.path.home=/usr/local/Cellar/[email protected]/5.6.16/libexec]
[2020-05-14T21:47:07,237][INFO ][o.e.p.PluginsService ] [vXW29Yn] loaded module [aggs-matrix-stats]
[2020-05-14T21:47:07,237][INFO ][o.e.p.PluginsService ] [vXW29Yn] loaded module [ingest-common]
[2020-05-14T21:47:07,237][INFO ][o.e.p.PluginsService ] [vXW29Yn] loaded module [lang-expression]
[2020-05-14T21:47:07,238][INFO ][o.e.p.PluginsService ] [vXW29Yn] loaded module [lang-groovy]
[2020-05-14T21:47:07,238][INFO ][o.e.p.PluginsService ] [vXW29Yn] loaded module [lang-mustache]
[2020-05-14T21:47:07,238][INFO ][o.e.p.PluginsService ] [vXW29Yn] loaded module [lang-painless]
[2020-05-14T21:47:07,238][INFO ][o.e.p.PluginsService ] [vXW29Yn] loaded module [parent-join]
[2020-05-14T21:47:07,238][INFO ][o.e.p.PluginsService ] [vXW29Yn] loaded module [percolator]
[2020-05-14T21:47:07,238][INFO ][o.e.p.PluginsService ] [vXW29Yn] loaded module [reindex]
[2020-05-14T21:47:07,238][INFO ][o.e.p.PluginsService ] [vXW29Yn] loaded module [transport-netty3]
[2020-05-14T21:47:07,238][INFO ][o.e.p.PluginsService ] [vXW29Yn] loaded module [transport-netty4]
[2020-05-14T21:47:07,239][INFO ][o.e.p.PluginsService ] [vXW29Yn] no plugins loaded
[2020-05-14T21:47:08,643][INFO ][o.e.d.DiscoveryModule ] [vXW29Yn] using discovery type [zen]
[2020-05-14T21:47:09,099][INFO ][o.e.n.Node ] initialized
[2020-05-14T21:47:09,099][INFO ][o.e.n.Node ] [vXW29Yn] starting ...
[2020-05-14T21:47:09,347][INFO ][o.e.t.TransportService ] [vXW29Yn] publish_address {127.0.0.1:9300}, bound_addresses {[::1]:9300}, {127.0.0.1:9300}
[2020-05-14T21:47:12,405][INFO ][o.e.c.s.ClusterService ] [vXW29Yn] new_master {vXW29Yn}{vXW29YnkRDaIb8XuGeKRxQ}{0aNOjaAGSGGLSXHQUS-lyg}{127.0.0.1}{127.0.0.1:9300}, reason: zen-disco-elected-as-master ([0] nodes joined)
[2020-05-14T21:47:12,425][INFO ][o.e.h.n.Netty4HttpServerTransport] [vXW29Yn] publish_address {127.0.0.1:9200}, bound_addresses {[::1]:9200}, {127.0.0.1:9200}
[2020-05-14T21:47:12,425][INFO ][o.e.n.Node ] [vXW29Yn] started
[2020-05-14T21:47:12,431][INFO ][o.e.g.GatewayService ] [vXW29Yn] recovered [0] indices into cluster_state
直接在瀏覽器輸入:http://localhost:9200/
安裝Kibana
➜ ~ brew search kibana
==> Formulae
kibana [email protected]
➜ ~ brew install [email protected]
==> Downloading https://mirrors.ustc.edu.cn/homebrew-bottles/bottles/kibana%405.6-5.6.16.catalina.bottle.1.tar.gz
==> Downloading from https://akamai.bintray.com/f4/f451a8784dc52182670152d040f6533d4dc2f1b251ef3797eed6c6ff565db8af?__gda__=exp=1589465020~hm
######################################################################## 100.0%
Warning: [email protected] has been deprecated!
==> Pouring [email protected]
==> Caveats
Config: /usr/local/etc/kibana/
If you wish to preserve your plugins upon upgrade, make a copy of
/usr/local/opt/[email protected]/plugins before upgrading, and copy it into the
new keg location after upgrading.
[email protected] is keg-only, which means it was not symlinked into /usr/local,
because this is an alternate version of another formula.
If you need to have [email protected] first in your PATH run:
echo 'export PATH="/usr/local/opt/[email protected]/bin:$PATH"' >> ~/.zshrc
To have launchd start [email protected] now and restart at login:
brew services start [email protected]
Or, if you don't want/need a background service you can just run:
/usr/local/opt/[email protected]/bin/kibana
==> Summary
/usr/local/Cellar/[email protected]/5.6.16: 37,391 files, 200MB
同樣的道理,配置好環境變量。
啓動kibana
➜ ~ kibana
log [13:56:55.842] [info][status][plugin:[email protected]] Status changed from uninitialized to green - Ready
log [13:56:55.901] [info][status][plugin:[email protected]] Status changed from uninitialized to yellow - Waiting for Elasticsearch
log [13:56:55.923] [info][status][plugin:[email protected]] Status changed from uninitialized to green - Ready
log [13:56:55.952] [info][status][plugin:[email protected]] Status changed from uninitialized to green - Ready
log [13:56:56.158] [info][status][plugin:[email protected]] Status changed from uninitialized to green - Ready
log [13:56:56.162] [info][listening] Server running at http://localhost:5601
log [13:56:56.163] [info][status][ui settings] Status changed from uninitialized to yellow - Elasticsearch plugin is yellow
log [13:57:01.165] [info][status][plugin:[email protected]] Status changed from yellow to yellow - No existing Kibana index found
log [13:57:02.456] [info][status][plugin:[email protected]] Status changed from yellow to green - Kibana index ready
log [13:57:02.457] [info][status][ui settings] Status changed from yellow to green - Ready
直接在瀏覽器輸入:http://localhost:5601/
添加數據
PUT /megacorp/employee/1
{
"first_name" : "John",
"last_name" : "Smith",
"age" : 25,
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
}
{
"_index": "megacorp",
"_type": "employee",
"_id": "2",
"_version": 1, // 版本
"result": "created", // 是新增還是修改
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"created": true
}
查詢數據
對着官方文檔一一的研究了一下它的一些語法與介紹。我個人覺得ElasticSearch的官方文檔還算比較過關的:https://www.elastic.co/guide/cn/elasticsearch/guide/current/foreword_id.html 學習起來基本毫無障礙。
POST /my_store/products/_bulk
{ "index": { "_id": 1 }}
{ "price" : 10, "productID" : "XHDK-A-1293-#fJ3" }
{ "index": { "_id": 2 }}
{ "price" : 20, "productID" : "KDKE-B-9947-#kL5" }
{ "index": { "_id": 3 }}
{ "price" : 30, "productID" : "JODL-X-1937-#pV7" }
{ "index": { "_id": 4 }}
{ "price" : 30, "productID" : "QQPX-R-3956-#aD8" }
GET /my_store/products/_search
{
"query" : {
"constant_score" : {
"filter" : {
"term" : {
"price" : 20
}
}
}
}
}
GET /my_store/products/_search
{
"query" : {
"constant_score" : {
"filter" : {
"term" : {
"productID" : "XHDK-A-1293-#fJ3"
}
}
}
}
}
GET /my_store/_analyze
{
"field": "productID",
"text": "XHDK-A-1293-#fJ3"
}
DELETE /my_store
PUT /my_store
{
"mappings" : {
"products" : {
"properties" : {
"productID" : {
"type" : "string",
"index" : "not_analyzed"
}
}
}
}
}
GET /my_store/products/_search
{
"query" : {
"filtered" : {
"filter" : {
"bool" : {
"should" : [
{ "term" : {"price" : 20}},
{ "term" : {"productID" : "XHDK-A-1293-#fJ3"}}
],
"must_not" : {
"term" : {"price" : 30}
}
}
}
}
}
}
GET /my_store/products/_search
{
"query" : {
"constant_score" : {
"filter" : {
"terms" : {
"price" : [20, 30]
}
}
}
}
}
GET /my_store/products/_search
{
"query" : {
"constant_score" : {
"filter" : {
"range" : {
"price" : {
"gte" : 20,
"lt" : 40
}
}
}
}
}
}
POST /my_index/posts/_bulk
{ "index": { "_id": "1" }}
{ "tags" : ["search"] }
{ "index": { "_id": "2" }}
{ "tags" : ["search", "open_source"] }
{ "index": { "_id": "3" }}
{ "other_field" : "some data" }
{ "index": { "_id": "4" }}
{ "tags" : null }
{ "index": { "_id": "5" }}
{ "tags" : ["search", null] }
GET /my_index/posts/_search
{
"query" : {
"constant_score" : {
"filter" : {
"exists" : { "field" : "tags" }
}
}
}
}
GET /my_index/posts/_search
{
"query" : {
"constant_score" : {
"filter": {
"missing" : { "field" : "tags" }
}
}
}
}
POST /cars/transactions/_bulk
{ "index": {}}
{ "price" : 10000, "color" : "red", "make" : "honda", "sold" : "2014-10-28" }
{ "index": {}}
{ "price" : 20000, "color" : "red", "make" : "honda", "sold" : "2014-11-05" }
{ "index": {}}
{ "price" : 30000, "color" : "green", "make" : "ford", "sold" : "2014-05-18" }
{ "index": {}}
{ "price" : 15000, "color" : "blue", "make" : "toyota", "sold" : "2014-07-02" }
{ "index": {}}
{ "price" : 12000, "color" : "green", "make" : "toyota", "sold" : "2014-08-19" }
{ "index": {}}
{ "price" : 20000, "color" : "red", "make" : "honda", "sold" : "2014-11-05" }
{ "index": {}}
{ "price" : 80000, "color" : "red", "make" : "bmw", "sold" : "2014-01-01" }
{ "index": {}}
{ "price" : 25000, "color" : "blue", "make" : "ford", "sold" : "2014-02-12" }
GET /cars/transactions/_search
{
"size" : 0,
"aggs" : {
"popular_colors111" : {
"terms" : {
"field" : "color.keyword"
}
}
}
}
GET /cars/transactions/_search
{
"size" : 0,
"aggs": {
"colors": {
"terms": {
"field": "color.keyword"
},
"aggs": {
"avg_price": {
"avg": {
"field": "price"
}
}
}
}
}
}
GET /cars/transactions/_search
{
"size" : 0,
"aggs": {
"colors": {
"terms": {
"field": "color.keyword"
},
"aggs": {
"avg_price": {
"avg": {
"field": "price"
}
},
"make": {
"terms": {
"field": "make.keyword"
}
}
}
}
}
}
GET /cars/transactions/_search
{
"size" : 0,
"aggs": {
"colors": {
"terms": {
"field": "color.keyword"
},
"aggs": {
"avg_price": { "avg": { "field": "price" }
},
"make" : {
"terms" : {
"field" : "make.keyword"
},
"aggs" : {
"min_price" : { "min": { "field": "price"} },
"max_price" : { "max": { "field": "price"} }
}
}
}
}
}
}
GET /cars/transactions/_search
{
"size" : 0,
"aggs":{
"price":{
"histogram":{
"field": "price",
"interval": 20000
},
"aggs":{
"revenue": {
"sum": {
"field" : "price"
}
}
}
}
}
}
GET /cars/transactions/_search
{
"size" : 0,
"aggs": {
"makes": {
"terms": {
"field": "make.keyword",
"size": 10
},
"aggs": {
"stats": {
"extended_stats": {
"field": "price"
}
}
}
}
}
}
GET /cars/transactions/_search
{
"size" : 0,
"aggs": {
"sales": {
"date_histogram": {
"field": "sold",
"interval": "month",
"format": "yyyy-MM-dd",
"min_doc_count" : 0,
"extended_bounds" : {
"min" : "2014-01-01",
"max" : "2014-12-31"
}
}
}
}
}
GET /cars/transactions/_search
{
"size" : 0,
"aggs": {
"sales": {
"date_histogram": {
"field": "sold",
"interval": "quarter",
"format": "yyyy-MM-dd",
"min_doc_count" : 0,
"extended_bounds" : {
"min" : "2014-01-01",
"max" : "2014-12-31"
}
},
"aggs": {
"per_make_sum": {
"terms": {
"field": "make.keyword"
},
"aggs": {
"sum_price": {
"sum": { "field": "price" }
}
}
},
"total_sum": {
"sum": { "field": "price" }
}
}
}
}
}
GET /cars/transactions/_search
{
"query" : {
"match" : {
"make" : "ford"
}
},
"aggs" : {
"colors" : {
"terms" : {
"field" : "color.keyword"
}
}
}
}
GET /cars/transactions/_search
{
"size" : 0,
"query" : {
"match" : {
"make" : "ford"
}
},
"aggs" : {
"single_avg_price": {
"avg" : { "field" : "price" }
},
"all": {
"global" : {},
"aggs" : {
"avg_price": {
"avg" : { "field" : "price" }
}
}
}
}
}
布爾過濾器
一個 bool
過濾器由三部分組成:
{
"bool" : {
"must" : [],
"should" : [],
"must_not" : [],
}
}
-
must
所有的語句都 必須(must) 匹配,與
AND
等價。 -
must_not
所有的語句都 不能(must not) 匹配,與
NOT
等價。 -
should
至少有一個語句要匹配,與
OR
等價。
就這麼簡單! 當我們需要多個過濾器時,只須將它們置入 bool
過濾器的不同部分即可。
幾個核心概念
- 集羣(Cluster)一組擁有共同的 cluster name 的節點。
- 節點(Node) 集羣中的一個 Elasticearch 實例。
- 索引(Index) 相當於關係數據庫中的database概念,一個集羣中可以包含多個索引。這個是個邏輯概念。
- 主分片(Primary shard) 索引的子集,索引可以切分成多個分片,分佈到不同的集羣節點上。分片對應的是 Lucene 中的索引。
- 副本分片(Replica shard)每個主分片可以有一個或者多個副本。
- 類型(Type)相當於數據庫中的table概念,mapping是針對 Type 的。同一個索引裏可以包含多個 Type。
- Mapping 相當於數據庫中的schema,用來約束字段的類型,不過 Elasticsearch 的 mapping 可以自動根據數據創建。
- 文檔(Document) 相當於數據庫中的row。
- 字段(Field)相當於數據庫中的column。
- 分配(Allocation) 將分片分配給某個節點的過程,包括分配主分片或者副本。如果是副本,還包含從主分片複製數據的過程。
- gateway: 代表es索引快照的存儲方式,es默認是先把索引存放到內存中,當內存滿了時再持久化到本地硬盤。gateway對索引快照進行存儲,當這個es集羣關閉再重新啓動時就會從gateway中讀取索引備份數據。es支持多種類型的gateway,有本地文件系統(默認),分佈式文件系統,Hadoop的HDFS和amazon的s3雲存儲服務。
索引數據結構
傳統數據庫爲特定列增加一個索引,例如B-Tree索引來加速檢索。Elasticsearch和Lucene使用倒排索引(inverted index)來達到相同目的,倒排索引中用到的數據結構是FST樹。
它的優點
-
Elasticsearch主要優勢是:速度快,使用方便,分佈式的,檢索,功能強大。
-
ES官方的想做的是ELK結合起來做日誌分析等工作。估計這也是它最多的應用場景。
-
Elasticsearch 現在的主要目標市場已經從站內搜索轉移到了監控與日誌數據的收集存儲和分析,也就是大家常談論的ELK。
-
Elasticsearch 現在主要的應用場景有三塊。站內搜索,主要和 Solr 競爭,屬於後起之秀。NoSQL json文檔數據庫,主要搶佔 Mongo 的市場,它在讀寫性能上優於 Mongo,同時也支持地理位置查詢,還方便地理位置和文本混合查詢,屬於歪打正着。監控,統計以及日誌類時間序的數據的存儲和分析以及可視化,這方面是引領者。
如何實現Master選舉的?
Elasticsearch的選舉是ZenDiscovery模塊負責的,通過多播或單播技術來發現同一個集羣中的其他節點並與它們連接。
一個節點如何選取它自己認爲的master節點?
它會對所有可以成爲master的節點(node.master: true)根據nodeId字典排序,,然後選出第一個(第0位)節點,暫且認爲它是master節點。
如果對某個節點的投票數達到一定的值(可以成爲master節點數n/2+1)並且該節點自己也選舉自己,那這個節點就是master。否則重新選舉一直到滿足上述條件。
集羣分片的讀寫操作流程
集羣分片的讀寫操作流程
第一:路由計算(routing)和副本一致性(replica)
- routing
Elasticsearch針對路由計算選擇了一個很簡單的方法,計算如下:
routing = hash(routing) % number_of_primary_shards
每個數據都有一個routing參數,默認情況下,就使用其_id值,將其_id值計算hash後,對索引的主分片數取餘,就是數據實際應該存儲到的分片ID
由於取餘這個計算,完全依賴於分母,所以導致Elasticsearch索引有一個限制,索引的主分片數,不可以隨意修改。因爲一旦主分片數不一樣,索引數據不可讀。
- 副本一致性(replica)
作爲分佈式系統,數據副本可算是一個標配。Elasticsearch數據寫入流程。自然涉及副本,在有副本配置的情況下,數據從發向Elasticsearch節點,到接到Elasticsearch節點響應返回,流向如下
-
客戶端請求發送給master Node1節點,這裏也可以發送給其他節點
-
Node1節點用數據的_id計算出數據應該存儲在shard0上,通過cluster state信息發現shard0的主分片在Node3節點上,Node1轉發請求數據給Node3,Node3完成數據的索引,索引過程在上篇博客中詳細介紹了。
-
Node3並行轉發數據給分配有shard0的副本分片Node1和Node2上。當收到任一節點彙報副本分片數據寫入成功以後,Node3即返回給初始的接受節點Node1,宣佈數據寫入成功。Node1成功返回給客戶端。
第二:shard的allocate配置
上文介紹了分片的索引過程,通過路由計算可以確定文本所在的分片id,那麼分片在集羣中的分配策略是如何確定的?
一般來說,某個shard分配在哪個節點上,是由Elasticsearch自動決定的。以下幾種情況會觸發分配動作:
- 新索引生成
- 索引的刪除
- 新增副本分片
- 節點增減引發的數據均衡
如何集成Bboss+Echart?
如何更高效的集成一些已經成型的開源框架呢?推薦一個比較好用的es+spring的框架,而且是基於Restful方式的,支持像mybatis的寫法。
<!-- ES start -->
<dependency>
<groupId>com.bbossgroups.plugins</groupId>
<artifactId>bboss-elasticsearch-spring-boot-starter</artifactId>
<version>6.1.1</version>
<exclusions>
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- ES end -->
<!-- 讓你輕鬆的搞定ECharts各種域對象 -->
<dependency>
<groupId>com.github.abel533</groupId>
<artifactId>ECharts</artifactId>
<version>3.0.0.6</version>
</dependency>
後面專門來用一篇描述對於bboss-elasticsearch-spring-boot-starter
的集成以及改造。
# ElasticSearch 配置
spring.elasticsearch.bboss.elasticsearch.rest.hostNames=elasticsearch-test.za.net:9200
<properties>
<property name="pieLoanSuccessAndGroupByProduct">
<![CDATA[
{
"query": {
"bool": {
"filter": {
"range": {
"gmt_created": {
"include_lower": true,
"include_upper": true,
"from": #[from],
"to": #[to]
}
}
},
"must": {
"match": {
"status": 5
}
}
}
},
"size": 0,
"aggs": {
"list": {
"terms": {
"field": "product_code"
}
}
}
}
]]>
</property>
</properties>
@Test
public void testSearchAgg() throws Exception {
String mappath = "esmapper/LoanApply.xml";
//創建加載配置文件的客戶端工具,用來檢索文檔,單實例多線程安全
ClientInterface clientInterface = bbossESStarter.getConfigRestClient(mappath);
Map<String, Object> params = new HashMap<String, Object>();
params.put("from", "2017-01-14 12:14:09");
params.put("to", "2018-05-14 12:14:09");
String path = index + "/" + type + "/_search";
ESAggDatas<LongAggHit> response = clientInterface.searchAgg(path,
"pieLoanSuccessAndGroupByProduct",
params,
LongAggHit.class,
"list");
log.info("response={}", JSONUtils.toFormatJsonString(response));
}
上面就是一個簡單的例子,後面可以專門爲這個開源項目做一個詳細的介紹,不過人家的文檔寫的也是非常的Nice的。https://esdoc.bbossgroups.com/#/quickstart
參考地址
- https://zhuanlan.zhihu.com/p/33671444
- https://yq.aliyun.com/articles/581877
- https://www.cnblogs.com/LBSer/p/4119841.html
- https://my.oschina.net/u/2935389/blog/754674
- https://blog.csdn.net/yangwenbo214/article/details/77802331
- https://www.jianshu.com/p/2cac077e05cf
如果大家喜歡我的文章,可以關注個人訂閱號。歡迎隨時留言、交流。如果想加入微信羣的話一起討論的話,請加管理員簡棧文化-小助手(lastpass4u),他會拉你們進羣。