抽象類比
MySql | Es |
---|---|
Table | Index(Type) |
Row | Document |
Column | Field |
Schema | Mapping |
SQL | DSL |
一些概念
cluster(集群)
一個ES集群由一個或多個節點(Node)組成,每個集群都有一個cluster name作為標識。
node(節點)
一個ES實例就是一個 node,一個機器可以有多個實例,所以並不能說一台機器就是一個 node,大多數情況下每個node運行在一個獨立的環境或虛擬機上。
index(索引)
即一系列 documents 的集合。每個索引可以有多個type,不過7.0之后將會被廢棄,略過。
mappings(映射)
映射, 就像數據庫中的 schema ,描述了文檔可能具有的字段或 屬性 、每個字段的數據類型—比如 string, integer 或 date —以及Lucene是如何索引和存儲這些字段的。
- 字符串: string
- 整數: byte, short, integer, long
- 浮點數: float, double
- 布爾型: boolean
- 日期: date
- keyword:存儲數據時候,不會分詞建立索引
- text:存儲數據時候,會自動分詞,並生成索引
shard(分片)
ES是分布式搜索引擎,每個索引有一個或多個分片,索引的數據被分配到各個分片上,相當於一桶水用了N個杯子裝。分片有助於橫向擴展,N個分片會被盡可能平均地(rebalance)分配在不同的節點上(例如你有2個節點,4個主分片(不考慮備份),那么每個節點會分到2個分片,后來你增加了2個節點,那么你這4個節點上都會有1個分片,這個過程叫 relocation,ES感知后自動完成)。分片是獨立的,對於一個 Search Request 的行為,每個分片都會執行這個 Request。
replica(復制)
可以理解為備份分片,相應地有 primary shard(主分片),主分片和備分片不會出現在同一個節點上(防止單點故障),默認情況下一個索引創建5個分片一個備份(即5primary+5replica=10個分片)。如果你只有一個節點,那么5個 replica 都無法分配(unassigned),此時cluster status會變成Yellow。
倒排索引
Elasticsearch 使用一種稱為 倒排索引 的結構,它適用於快速的全文搜索。一個倒排索引由文檔中所有不重復詞的列表構成,對於其中每個詞,有一個包含它的文檔列表。
analysis
Document 中的數據是如何轉變成倒排索引的,以及查詢語句是如何轉換成一個個詞(Term)使高效率文本搜索變得可行,這種轉換數據的過程就稱為文本分析(analysis)。
elasticsearch會用某種算法(Tokenizer)對要建索引的文檔進行分析, 從文檔中提取出若干Token(詞元), 這些算法稱為Tokenizer(分詞器), 這些Token會被進一步處理, 比如轉成小寫等, 這些進一步的處理算法被稱為Filter(過濾器), 被處理后的結果被稱為Term(詞), 文檔中包含了幾個這樣的Term被稱為Frequency(詞頻)。 引擎會建立Term和原文檔的Inverted Index(倒排索引), 這樣就能根據Term很快到找到源文檔了。
文本分析(analysis)工作由analyzer(分析器)組件負責。analyzer由一個分詞器(tokenizer)和0個或者多個過濾器(filter)組成,也可能會有0個或者多個字符映射器(character mappers)組成。
tokenizer用來把文本拆分成一個個的Token。Token包含了比較多的信息,比如Term在文本的中的位置及Term原始文本,以及Term的長度。文本經過tokenizer處理后的結果稱為token stream。token stream其實就是一個個Token的順序排列。token stream將等待着filter來處理。
filter鏈將用來處理Token Stream中的每一個token。這些處理方式包括刪除Token, 改變Token,甚至添加新的Token。比如變小寫,去掉里面的HTML標記, 這些處理的算法被稱為Character Filter(字符過濾器)
ES集群狀態有三種:
-
Green:所有主分片和備份分片都准備就緒(分配成功),即使有一台機器掛了(假設一台機器一個實例),數據都不會丟失,但會變成Yellow狀態
-
Yellow:所有主分片准備就緒,但存在至少一個主分片(假設是A)對應的備份分片沒有就緒,此時集群屬於警告狀態,意味着集群高可用和容災能力下降,如果剛好A所在的機器掛了,並且你只設置了一個備份(已處於未就緒狀態),那么A的數據就會丟失(查詢結果不完整),此時集群進入Red狀態
-
Red:至少有一個主分片沒有就緒(直接原因是找不到對應的備份分片成為新的主分片),此時查詢的結果會出現數據丟失(不完整)
replica作用:
- 容災:primary分片丟失,replica分片就會被頂上去成為新的主分片,同時根據這個新的主分片創建新的replica,集群數據安然無恙;
- 提高查詢性能:replica和primary分片的數據是相同的,所以對於一個query既可以查主分片也可以查備分片,在合適的范圍內多個replica性能會更優(但要考慮資源占用也會提升[cpu/disk/heap]),另外index request只能發生在主分片上,replica不能執行index request。
對於一個索引,除非重建索引否則不能調整分片的數目(主分片數, number_of_shards),但可以隨時調整 replica 數(number_of_replicas)。
安裝運行
通過 docker 啟動一個單節點集群
$ docker run -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:6.7.2
與 Elasticsearch 交互
使用 RESTful API 通過端口 9200 和 Elasticsearch 進行通信
$ curl -X<METHOD> http://localhost:9200/<PATH>?<QUERY_STRING> -d '<BODY>'
操作索引
新建索引時可以指定設置或者映射,也可以不指定自動生成
$ PUT foo_index
{
"settings": {
"number_of_shards" : 1, #每個索引的主分片數,默認值是 5 。這個配置在索引創建后不能修改。
"number_of_replicas" : 0 #每個主分片的副本數,默認值是 1 。對於活動的索引庫,這個配置可以隨時修改。
},
"mappings": {
"type_one": { ... any mappings ... },
"type_two": { ... any mappings ... },
...
}
}
修改索引設置
$ PUT foo_index/_settings
{
"number_of_replicas": 1
}
修改索引映射
$ PUT foo_index/_mappings/_doc
{
"properties": {...}
}
刪除索引
$ DELETE foo_index
操作文檔
使用put新建文檔項指定id為1
$ PUT foo_index/_doc/1
{
"name": "demo 1",
"body": "demo foo bar"
}
使用post可以不指定id來新建文檔,自動生成id
$ POST foo_index/_doc
{
"name": "demo test",
"body": "demo test"
}
查看id=1的文檔
$ GET foo_index/_doc/1
搜索
使用 curl -X GET foo_index/_search -d 'body'
來搜索文檔
match_all匹配所有文檔,等價於空查詢{}
{
"query": {
"match_all": {}
}
}
mathc匹配包含,如果在一個精確值的字段上使用match,例如數字、日期、布爾或者一個 not_analyzed 字符串字段,那么它將會精確匹配給定的值:
{
"query": {
"match": {
"name": "demo"
}
}
}
多字段match使用multi_match
{
"multi_match": {
"query": "full text search",
"fields": [ "title", "body" ]
}
}
term查詢被用於精確值匹配,這些精確值可能是數字、時間、布爾或者那些 not_analyzed 的字符串,term 查詢對於輸入的文本不分析 ,所以它將給定的值進行精確查詢
{
"query": {
"term": {
"name": "demo"
}
}
}
terms查詢被用於匹配多個精確值
{
"query": {
"terms": {
"name": ["demo", "demo1"]
}
}
}
合並(bool)查詢可以組合多種查詢方法
{
"bool": {
"must": { "match": { "tweet": "elasticsearch" }},
"must_not": { "match": { "name": "mary" }},
"should": { "match": { "tweet": "full text" }},
"filter": { "range": { "age" : { "gt" : 30 }} }
}
}