ElasticSearch 學習筆記

ElasticSearch 學習筆記

基本概念

  1. index : 索引 一個索引中可以有多個type (建議一個index中只有一個type , 因爲它的存儲結構是將一個index的所有type的field整合成一個大的json , 當多個type的field 都不同時,那麼一個docment的自己的field是有值的其他的docment的field都是null,這樣會浪費很多存儲空間,但是在elasticSearch7中將type給忽略了,也就是index下可以直接有docment,這樣就不會出現feild爲空而造成的存儲空間浪費現象)
  2. type : 類型 一個type中可以有很多docment
  3. docment : 文檔 es中最小數據存儲單元
  4. field : 文檔內的一個屬性
  5. mapping : 映射 ?
  6. primary shard : 主分片存儲 (存儲結構詳解2)
  7. replica shard : 分片副本,作爲主分分片的副本存在,與主分片數據一致(容錯與負載)
  8. node : 部署節點,多節點部署會形成集羣

倒排索引

  1. 倒排索引:

    id name
    1 北京布鞋
    2 南京布鞋
    3 澳洲皮鞋

    正排索引的搜索是按照一條文檔一條文檔進行匹配查詢(先查id再匹配判斷)

    根據以上的正排索引我們會生成按name分詞的倒排索引

    name doc1 doc2 Doc3
    北京 1 0 0
    南京 0 1 0
    澳洲 0 0 1
    布鞋 1 1 0

    倒排索引是直接進行匹配判斷,獲取到文檔ID後,根據文檔ID再去查詢正排索引獲取數據

    倒排索引在查詢語句分析出後,纔去確認創建那個filed的倒排索引

timeout 超時

設置timeout時間,在超過這個時間之後會將這個時間段內查詢到的數據返回,後續的還會查詢但是不會返回,

所以在查詢大量數據的是時候進來使用分片查詢

from : 1 ,開始位置1

size : 100 , 查詢100條

Query 與 filter 的區別

query 翻譯是查詢 , 會有相關度計算 (相關度算法後面回解釋)

filter 翻譯是過濾 , 只有結果沒有相關度計算

query

全文檢索

  1. 命令

    1. 6 版本 GET /index(索引) /type(類型)/_search
    2. 7 版本 GET /index(索引)/_search
  2. 查詢body

    {
    	"query":{
    		"match":{
    			"name":"張三"
    		}
    	}
    }
    
  3. 結果集分析

    {
      "took" : 1,
      "timed_out" : false,
      "_shards" : {
        "total" : 1,
        "successful" : 1,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : {
          "value" : 1,
          "relation" : "eq"
        },
        "max_score" : 2.271394,
        "hits" : [
          {
            "_index" : "user",
            "_type" : "user",
            "_id" : "2",
            "_score" : 2.271394,
            "_source" : {
              "name" : "張三",
              "age" : 21,
              "desc" : "這是一個測試用戶"
            }
          }
        ]
      }
    }
    
    
    field 描述
    took 查詢花費時間單位 毫秒
    timed_out 是否開啓timeout
    _shards.total 查詢了多少shard
    _shards.successful 成功的查詢了多少shard
    _shards.failed 多少個shard沒有被查詢到
    hits.max_score 最大相關度事多少
    hits.hits 查詢結果(是經過封裝過後的)
    hits.hits._index 該數據的索引
    hits.hits._type 該數據的類型
    hits.hits._score 該數據的相關度
    hits.hits._id 該docment的ID
    hits.hits._source 該docment的內容

短語檢索

  1. 命令與全文檢索相同

  2. 查詢body

    {
      "query":{
        "macth_phrase":{
          "name":"張三"
        }
      }
    }
    
  3. 結果分析與全文檢索一致

高亮檢索

  1. 命令與全文檢索一致

  2. 查詢body

    {
    	"query":{
    		"match": {
    		  "name": "張"
    		}
    	},
    	"highlight": {
    	  "fields": {
    	    "name": {}
    	  }
    	}
    }
    
  3. 結果集分析

    {
      "took" : 1,
      "timed_out" : false,
      "_shards" : {
        "total" : 1,
        "successful" : 1,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : {
          "value" : 1,
          "relation" : "eq"
        },
        "max_score" : 2.271394,
        "hits" : [
          {
            "_index" : "user",
            "_type" : "user",
            "_id" : "2",
            "_score" : 2.271394,
            "_source" : {
              "name" : "張三",
              "age" : 21,
              "desc" : "這是一個測試用戶"
            },
            "highlight" : {
              "name" : [
                "<em>張</em>三"
              ]
            }
          }
        ]
      }
    }
    
    
    field 描述
    highlight 標紅字的field
    name index的一個field 與 source中的name是一個意義

分組檢索

  1. 命令 同上

  2. 查詢body 按name 進行分組

    {
    	"aggs": {
    	  "group_by_name": {
    	    "terms": {
    	      "field": "age"
    	    }
    	  }
    	}
    }
    
  3. 結果分析

    {
      "took" : 2,
      "timed_out" : false,
      "_shards" : {
        "total" : 1,
        "successful" : 1,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : {
          "value" : 3,
          "relation" : "eq"
        },
        "max_score" : 1.0,
        "hits" : [
          {
            "_index" : "user",
            "_type" : "user",
            "_id" : "2",
            "_score" : 1.0,
            "_source" : {
              "name" : "張三",
              "age" : 21,
              "desc" : "這是一個測試用戶"
            }
          },
          {
            "_index" : "user",
            "_type" : "user",
            "_id" : "3",
            "_score" : 1.0,
            "_source" : {
              "name" : "李四",
              "age" : 80,
              "desc" : "這是一個老人"
            }
          },
          {
            "_index" : "user",
            "_type" : "user",
            "_id" : "1",
            "_score" : 1.0,
            "_source" : {
              "name" : "測試用戶1",
              "age" : 23,
              "desc" : "這是一個用戶1"
            }
          }
        ]
      },
      "aggregations" : {
        "group_by_name" : {
          "doc_count_error_upper_bound" : 0,
          "sum_other_doc_count" : 0,
          "buckets" : [
            {
              "key" : 21,
              "doc_count" : 1
            },
            {
              "key" : 23,
              "doc_count" : 1
            },
            {
              "key" : 80,
              "doc_count" : 1
            }
          ]
        }
      }
    }
    
    
    feild 描述
    aggregations.buckets.key 分組值
    aggregations.buckets.value 分組計數

    平均值的檢索

    1. 命令 同上

    2. 查詢body

      {
      	"aggs": {
         "avg_age": {
              "avg": {
                "field": "age"
              }
            }
      	}
      }
      
    3. 結果分析

      {
        "took" : 0,
        "timed_out" : false,
        "_shards" : {
          "total" : 1,
          "successful" : 1,
          "skipped" : 0,
          "failed" : 0
        },
        "hits" : {
          "total" : {
            "value" : 3,
            "relation" : "eq"
          },
          "max_score" : 1.0,
          "hits" : [
            {
              "_index" : "user",
              "_type" : "user",
              "_id" : "2",
              "_score" : 1.0,
              "_source" : {
                "name" : "張三",
                "age" : 21,
                "desc" : "這是一個測試用戶"
              }
            },
            {
              "_index" : "user",
              "_type" : "user",
              "_id" : "3",
              "_score" : 1.0,
              "_source" : {
                "name" : "李四",
                "age" : 80,
                "desc" : "這是一個老人"
              }
            },
            {
              "_index" : "user",
              "_type" : "user",
              "_id" : "1",
              "_score" : 1.0,
              "_source" : {
                "name" : "測試用戶1",
                "age" : 23,
                "desc" : "這是一個用戶1"
              }
            }
          ]
        },
        "aggregations" : {
          "avg_age" : {
            "value" : 41.333333333333336
          }
        }
      }
      
      
      field 描述
      aggregations.avg_age avg_age是我們查詢的時候自定義的名稱與body中的名稱相對應
      aggregations.avg_age.value 針對於這個avg_age的平均值也就是所有用戶的平均age

區間檢索

  1. 命令同上

  2. 檢索body

    {
      "query": {
        "range": {
          "age": {
            "gte": 20,
            "lte": 30
          }
        }
      }
    }
    
  3. 結果分析與全文檢索一致

批量查詢

  1. 命令 GET /_mget

  2. 查詢body

    {
      "docs":[
        {
          "_index":"user",
          "_type":"user",
          "_id":1
        },
        {
          "_index":"test1",
          "_type":"test1",
          "_id":1
        }
        ]
    }
    
  3. 結果分析

    {
      "docs" : [
        {
          "_index" : "user",
          "_type" : "user",
          "_id" : "1",
          "_version" : 5,
          "_seq_no" : 6,
          "_primary_term" : 1,
          "found" : true,
          "_source" : {
            "name" : "測試用戶111",
            "age" : 23,
            "desc" : "這是一個用戶1111"
          }
        },
        {
          "_index" : "test1",
          "_type" : "test1",
          "_id" : "1",
          "_version" : 1,
          "_seq_no" : 0,
          "_primary_term" : 1,
          "found" : true,
          "_source" : {
            "name" : "test1"
          }
        }
      ]
    }
    
    

    多個index下的結果可以i 一起返回,節省io請求,優化方式之一

查詢排序

當我們使用一個字符串進行排序的時候,實際上是使用的field分詞之後的單詞進行排序的,而不是那字符串本身進行排序,我們需要將排序字段單獨設置一個mapping index設置爲false ,不索引,使用字段本身進行排序

查詢緩存

我們在查詢的時候會進行倒排索引的查詢,在查詢倒排索引的時候會將查詢結果以二進制數組的方式作爲緩存

例如我們上面的倒排索引, 查詢南京就會出現[0,1,0]這樣的數組,當下一個一模一樣的查詢過來時,不會再查詢索引表,而是直接使用這個緩存

文檔替換與刪除

  1. 文檔是有_version屬性的
  2. put 在全量替換的時候就是將之前的docment標記爲刪除並新創建一個docment,version會拷貝過來
  3. 用戶在刪除docment的時候es並沒有直接將docment刪除掉,只是將它標記爲delete狀態而已
  4. 當新的文檔進來而內存不足時會將標記爲delete的數據刪除

ES路由

### 增刪改路由
  1. 路由是在分佈式架構下,分片存儲,備份存儲的前提下的解決方案
  2. 路由算法 shard = hash(routing)%number_of_primary_shards
  3. routing 默認是原數據_id ,但是我們可以進行指定
  4. 在指定routing的時候只可以指定一次,也就是一個index的有且只有一個,中間不可以發生改變

查詢路由

  1. 我們在查詢的時候會先走增刪改路由,來確認次數據是屬於那個primary shard 的數據
  2. 得知數據在那個primary shard 的時候我們的primary shard 有至少一個replica shard ,但是我們是用的那個shard呢?
  3. 這是我們可以不指定路由,10個查詢請求可能有3個在primary shard 上 ,7個在replica shard上
  4. 我們在請求的時候指定查詢routing的時候着10個請求就只會在一個shard上了
  5. 爲什麼要指定查詢路由?在主從數據同步的時候會出現基礎數據順序不一致的情況,那麼我們第一次查詢可能是123,但是第二次查詢如果不在同一個shard上是就可能是213,所以我們在查詢的時候進來要指定查詢路由
  6. 指定查詢路由 GET /user/user/_search?routing= _id

分詞

  1. 分詞器就就是將一段話按詞語進行切分,時態轉換,單複數轉換

  2. es中按切分的詞語創建了倒排索引的表

  3. 分詞器的組成

    1. chardcter filter: 分詞之前的預處理 (例如: 過濾標籤 , 特殊字符轉化等)
    2. tokenizer: 進行分詞
    3. token filter : 去除停用詞,將一些沒有意義的詞進行剔除,同義詞轉換
  4. elasticsearch的內置分詞器

    1. standard analyzer : 大小寫轉換 空格拆分 (默認)

    2. simple analyzer : 簡單分詞器 空格下劃線拆分

    3. whitespace analyzer :

    4. Language analyzer : 特定語言分詞器

Mapping 映射

mapping的概念

1. mapping是index的元數據,每個field都有自己的mapping,它決定了數據類型,建立索引的行爲,還有搜索行爲
2. mapping的基礎類型
  	1. text
  	2. keyword 不會進行分詞
  	3. integer
  	4. long
  	5. date 需要指定format格式
  	6. float
  	7. double
3. <font color="red">不可修改,重點,重點,重點</font>

查看mapping

  1. 命令 GET /index/_mapping/type

  2. 結果解析

    {
      "user" : {
        "mappings" : {
          "properties" : {
            "age" : {
              "type" : "long"
            },
            "desc" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            },
            "name" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              },
              "fielddata" : true
            }
          }
        }
      }
    }
    
    
    field 描述
    user index索引
    mappings 該索引下所有的field的mapping設置
    properties 屬性集合
    age/name 我們的屬性
    type field對應的類型
    fields 一個屬性可以在屬性內再次設置它的mapping
    fidlds.keyword 屬性的第二個mapping這是不是它的mapping而是name.keyword的mapping要使用這個mapping的時候查詢條件是name.keyword不是name

mapping的創建

PUT /user
{
  "mappings": {
    "properties": {
      "name":{
        "type": "text",
        "analyzer": "english"
      }
    }
  }
}

mapping的修改

PUT /user/_mapping
{
  "properties":{
    "name":{
      "type":"text"
    ,
      "fielddata":true
    }
  }
}

query相關度算法

  1. TF 算法:搜索文本中各個詞條在field中出現的次數,出現的越多,相關度越高
  2. IDF 算法: 搜索文本中的各個詞條在所有的field中出現的次數,出現越多相關度越低,(物以稀爲貴)
  3. Field-length norm : field長度越長相關度越低 , 這個單詞在這個field中的重要性越低

elasticSearch 存儲結構

在這裏插入圖片描述

elasticSearch 存儲結構特點

  1. 一個index可以設置多個primary shard 與多個 replica shard, 總的分片數是 peimary shard * replica shard 數(primay shard 是在創建索引是就固定的不可修改 , replica shard 是可以修改的)
  2. 一個node節點上對於一份數據只會存儲一次,也就是說,一個node上只有index的中的一個 primary shard 或一個 replica shard (用來保障數據的高可用,提升吞吐量)不同的index的primary shard可以在一個節點上
  3. 在創建index的時候沒有設置shard的時候默認是 5 個 primary shard 每個primary shard 有一個 replica sahrd
  4. shard 負載均衡
  5. 請求路由
  6. 集羣擴容
  7. shard重新分配

擴容方案

#### 	水平擴容

​ 將現有集羣的內存擴大

垂直擴容(建議)

​ 增加節點加入集羣,當每個節點上只有一個shard的時候就遇到了瓶頸,這時我們可以增加replica shard來再次增加性能

shard重新分配(rebalance)

當機器增加或減少是集羣會將已有的shard重新分配到現有機器上保持負載均衡,這是需要一個

master節點

在重新分配的時候需要一個機器來計算並調配資源所以集羣中需要一個master節點

管理索引的元數據,默認情況下集羣回自動選舉一個master節點

master節點不會去承載請求(一般不會去承載數據)

master選舉

  1. 當master節點宕機的時候集羣狀態是red

  2. 自動選舉一個新的master

  3. 如果有primary shard丟失,會將丟失的primary shard 的replica shard 提升爲primary shard

  4. 這是這個primary shard 無法在創建新的replica shard的時候集羣是yellow狀態

  5. 宕機的節點重啓之後會rebalance,根據primaryshard進行數據恢復

節點對等的分佈式架構

  1. 每個節點都可以接收到所有的請求,無論我這份節點上是否有該索引的shard,我都會接受這個請求(路由的時候不會區分primary shard還是replica shard)
  2. 自定請求路徑,當這個節點接受到非本節點的index的請求時,會將請求自定義到對應的節點上
  3. 相應收集,當這個請求所需要的數據不止在一個節點上的時候,該節點會將請求路由到有所有數據的節點,並收集返回的數據進行二次處理(尤其是在分頁的時候)

併發衝突

樂觀鎖控制

  1. es中的元數據有version 在,docment發生修改之後就會加1,新的修改過來時會先判斷version,不對就重新讀區

docment寫入流程

寫入
1.buffer滿了或到refresh_interval之後commint point
2.segment會將數據存到系統內存中
6.fsync強制刷新到磁盤
3.打開這個片段供查詢訪問
4.清空buffer
5.新的查詢操作到segment搜索
記錄日誌
應用程序 java等
buffer緩存
新的index segment
OS cache
OS disk
tranlog 文件

es底層使用的是lucene,lucene底層index是分爲多個segment,每個segment都會存儲一部分數據,

buffer始終存在,不停的寫入刷新到segment中,磁盤寫入完成後清空buffer

buffer每次寫滿或refresh_interval之後都會將數據commint到一個新的index segment中去

刪除會將數據記錄在.del文件中,查詢結果會去匹配這個文件,將刪除的數據去掉,不會返回,當commint point 的時候將標記爲deleted的數據從內存及磁盤上刪除

refresh_interval:內存間隔多長時間數據會執行以上所有操作

refresh_interval默認設置是1s,在設置的時候需要加單位設置 1s,2ms,3min等

當translog文件到達一定大小時會將buffer中的數據新建一個segment,並進行commint point寫入OS cache及磁盤上,同時記錄那些segment提交過,translog日誌文件清空,這個過程叫做flush

translog內記錄的數據是包含沒有fsync的segment中的數據的,OS cache中的數據也是依靠translog內的數據恢復的

flush觸發機制30分鐘或translog過大

commint point 的時候會將已有的segment merge成一個segment刷新到OS cache和磁盤上,並刪除之前的segment這樣會減少segment文件過多的問題

問題

  1. 一個index下如果有多個type 那麼docment_id就會衝突?

    答:這時不可以使用數據的ID來設置,需要使用elasticsearch生成的ID否則方法id兩個表中的某一條數據ID重複elasticsearch只會存儲一條數據(不管是那個版本禁止一個index下有多個type)

  2. Elasticsearch中每個shard上的數據最優大小是多少有算法嗎?(未解決)

    最後的問題我依舊沒有解決,如果有了解的小夥伴記得私信一下我哦😊😊😊😊

發佈了9 篇原創文章 · 獲贊 2 · 訪問量 3736
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章