ElasticSearch基本簡介(一)

一、ES簡介

1,什麼是ES

  ElasticSearch是一個基於Lucene的搜索服務器。它提供了一個分佈式的全文搜索引擎,其對外服務是基於RESTful web接口發佈的。Elasticsearch是用Java開發的應用,並作爲Apache許可條款下的開放源碼發佈,是當前流行的企業級搜索引擎。設計用於雲計算中,能夠達到近實時搜索,穩定,可靠,快速,安裝使用方便。

2,ES的相關概念

a)cluster

  cluster集羣。ElasticSearch集羣由一或多個節點組成,其中有一個主節點,這個主節點是可以通過選舉產生的,主從節點是對於集羣內部來說的。ElasticSearch的一個概念就是去中心化,字面上理解就是無中心節點,這是對於集羣外部來說的,因爲從外部看ElasticSearch集羣,在邏輯上是個整體,你與集羣中的任何一個節點通信和與整個ElasticSearch集羣通信是等價的。也就是說,主節點的存在不會產生單點安全隱患、併發訪問瓶頸等問題。

b)shards

  primary shard:代表索引的主分片,ElasticSearch可以把一個完整的索引分成多個primary shard,這樣的好處是可以把一個大的索引拆分成多個分片,分佈存儲在不同的ElasticSearch節點上,從而形成分佈式存儲,併爲搜索訪問提供分佈式服務,提高併發處理能力primary shard的數量只能在索引創建時指定並且索引創建後不能再更改primary shard數量(重新分片需要重新定義分片規則)。es5.x之後默認爲5,es7.x默認爲1。

c)replicas

  replica shard:代表索引主分片的副本,ElasticSearch可以設置多個replica shard。replica shard的作用:一是提高系統的容錯性,當某個節點某個primary shard損壞或丟失時可以從副本中恢復。二是提高ElasticSearch的查詢效率,ElasticSearch會自動對搜索請求進行負載均衡,將併發的搜索請求發送給合適的節點,增強併發處理能力。可取值爲0~n,默認爲1。

d)Index

  索引。相當於關係型數據庫中的表。其中存儲若干相似結構的Document數據。如:客戶索引,訂單索引,商品索引等。ElasticSearch中的索引不像數據庫表格一樣有強制的數據結構約束,在理論上,可以存儲任意結構的數據。但了爲更好的爲業務提供搜索數據支撐,還是要設計合適的索引體系來存儲不同的數據。

e)Type

  類型。每個索引中都必須有唯一的一個Type,Type是Index中的一個邏輯分類。ElasticSearch中的數據Document是存儲在索引下的Type中的。

  注意:ElasticSearch5.x及更低版本中,一個Index中可以有多個Type。ElasticSearch6.x版本之後,type概念被弱化,一個index中只能有唯一的一個type。且在7.x版本之後,刪除type定義。

f)Document

  文檔。ElasticSearch中的最小數據單元。一個Document就是一條數據,一般使用JSON數據結構表示。每個Index下的Type中都可以存儲多個Document。一個Document中可定義多個field,field就是數據字段。如:學生數據({"name":"張三", "age":20, "gender":"男"})。

g)反向索引(倒排索引)

  對數據進行分析,抽取出數據中的詞條,以詞條作爲key,對應數據的存儲位置作爲value,實現索引的存儲。這種索引稱爲倒排索引。倒排索引是Document寫入ElasticSearch時分析維護的

  

 3,比數據庫做搜索的優勢

  • 數據庫查詢複雜度高。比如:like '%關鍵字%'不能命中索引,搜索複雜度高
  • 數據庫關鍵字的搜索不全面,搜索結果不符合要求。比如:搜索商品爲'筆記本電腦',不能搜索到只有'筆記本'或者只有'電腦'的數據
  • 數據庫搜索的效率問題。數據量越大,查詢效率越低。

二、ElasticSearch索引操作

1,查詢健康狀態

  GET _cat/health?v

  

  其中status的狀態分爲三種:green、yellow和red

  • green:每個索引的primary shard和replica shard都是active的
  • yellow:每個索引的primary shard都是active的,但部分的replica shard不是active的。比如:當前只有兩個node結點,需要創建大於等於兩個repica shard副分片,由於主分片和副分片均不能在同一個結點上,所有必定有副分片不能正常的active。
  • red:不是所有的索引的primary shard都是active狀態的。
#查看健康狀態
GET _cat/health?v
#查看節點信息
GET _cat/nodes?v
#查看索引信息
GET _cat/indices?v
#查看分片信息
GET _cat/shards?v

2,創建索引

#創建my_index索引(settings可以省略),創建後shards分片數不能修改,只能修改shards副本數
PUT my_index
{
  "settings": {
    "number_of_shards": 5,
    "number_of_replicas": 1
  }
}

  在ElasticSearch中,默認的創建索引的時候,會分配5個primary shard,併爲每個primary shard分配一個replica shard(在ES7版本後,默認創建1個primary shard)。在ElasticSearch中,默認的限制是:如果磁盤空間不足15%的時候,不分配replica shard。如果磁盤空間不足5%的時候,不再分配任何的primary shard。ElasticSearch中對shard的分佈是有要求的。ElasticSearch儘可能保證primary shard平均分佈在多個節點上。Replica shard會保證不和他備份的那個primary shard分配在同一個節點上

3,修改索引(副分片數)

#修改索引
PUT my_index/_settings
{
  "number_of_replicas": 2
}

  注意:索引一旦創建,primary shard數量不可變化,可以改變replica shard數量。

4,刪除索引

DELETE my_index

5,查看索引信息

  GET _cat/indices?v

  

三、ElasticSearch中Document相關操作

1,新增Document

  在索引中增加文檔。在index中增加document。

  ElasticSearch有自動識別機制。如果增加的document對應的index不存在,自動創建index;如果index存在,type不存在,則自動創建type。如果index和type都存在,則使用現有的index和type。

a)PUT

  PUT  索引名/類型名/唯一ID{字段名:字段值}

#如果當前id已經存在,那麼就是修改,如果不存在就是新增
PUT my_index/_doc/1 { "name":"test_doc_01", "remark":"first test elastic search", "order_no":1 }

  

  如果當前索引中的document的id已經存在,那麼就是修改,如果不存在就是新增。但是如果此時id已經存在,想要強制新增會報錯,強制新增的語法爲:

  PUT 索引名/類型名/唯一ID/_create{字段名:字段值}   或者是  PUT 索引名/類型名/唯一ID?op_type=create{字段名:字段值}

b)POST

  此操作爲ElasticSearch自動生成id的新增Document方式。此語法格式和PUT請求的數據新增,只有唯一的區別,就是可以自動生成主鍵id,其他的和PUT請求新增數據完全一致。

  POST 索引名/類型名[/唯一ID]{字段名:字段值}

#此時,如果新增時唯一id(2)不存在就是新增,如果唯一id(2)存在就是修改。這個與PUT相同
#可以直接變爲沒有id,會隨機生成一個GUID作爲id
POST my_index/_doc { "name":"test_doc_02", "remark":"second test elastic search", "order_no":2 }

2,查詢Document

a)GET 通過ID查詢

  GET 索引名/類型名/唯一ID

GET my_index/_doc/1

b)GET _mget批量查詢

  批量查詢可以提高查詢效率。推薦使用(相對於單數據查詢來說)。

#語法
GET 索引名/類型名/_mget
{
  "docs" : [
    {
     "_id" : "唯一ID值"
    },
{
     "_id" : "唯一ID值"
    }
  ]
}

3,修改Document

a)全量替換(同新增)

  PUT|POST 索引名/類型名/唯一ID{字段名:字段值}

  本操作相當於覆蓋操作。全量替換的過程中,ElasticSearch不會真的修改Document中的數據,而是標記ElasticSearch中原有的Document爲deleted狀態,再創建一個新的Document來存儲數據,當ElasticSearch中的數據量過大時,ElasticSearch後臺回收deleted狀態的Document。

PUT my_index/_doc/1
{
   "name":"test_doc_01111",
   "remark":"first 111",
   "order_no":1111
}

b)更新Document

  POST 索引名/類型名/唯一ID/_update{doc:{字段名:字段值}}

  只更新某Document中的部分字段。這種更新方式也是標記原有數據爲deleted狀態,創建一個新的Document數據,將新的字段未更新的原有字段組成這個新的Document,並創建。對比全量替換而言,只是操作上的方便,在底層執行上幾乎沒有區別。

POST my_index/_doc/1/_update
{
   "doc":{
      "name":" test_doc_01_for_update"
   }
}

4,刪除Document

  DELETE 索引名/類型名/唯一ID

  ElasticSearch中執行刪除操作時,ElasticSearch先標記Document爲deleted狀態,而不是直接物理刪除。當ElasticSearch存儲空間不足或工作空閒時,纔會執行物理刪除操作。標記爲deleted狀態的數據不會被查詢搜索到。

DELETE my_index/_doc/2

5,bulk批量增刪改

定義:

POST _bulk
{ "action_type" : { "metadata_name" : "metadata_value" } }
{ document datas | action datas }
action_typecreate: 強制創建,相當於PUT 索引名/類型名/唯一ID/_create
    index : 普通的PUT操作,相當於創建Document或全量替換
    update: 更新操作(partial update),相當於 POST 索引名/類型名/唯一ID/_update
    delete: 刪除操作

案例:

#如果index和type爲同一個可以提出來,此時創建ID爲111,覆蓋ID爲1,修改ID爲2,刪除ID爲3
POST my_index/_doc/_bulk
{"create":{"_id":111}}
{"name":"zs","age":15}
{"index":{"_id":1}}
{"name":"first","sort":1}
{"update":{"_id":2}}
{"doc":{"sort":2}}
{"delete":{"_id":3}}

  注意bulk語法中要求一個完整的json串不能有換行不同的json串必須使用換行分隔。多個操作中,如果有錯誤情況,不會影響到其他的操作,只會在批量操作返回結果中標記失敗。bulk語法批量操作時,bulk request會一次性加載到內存中,如果請求數據量太大性能反而下降(內存壓力過高),需要反覆嘗試一個最佳的bulk request size。一般從1000~5000條數據開始嘗試,逐漸增加。如果查看bulk request size的話,一般是5~15MB之間爲好。

  bulk語法要求json格式是爲了對內存的方便管理,和儘可能降低內存的壓力。如果json格式沒有特殊的限制,ElasticSearch在解釋bulk請求時,需要對任意格式的json進行解釋處理,需要對bulk請求數據做json對象會json array對象的轉化,那麼內存的佔用量至少翻倍,當請求量過大的時候,對內存的壓力會直線上升,且需要jvm gc進程對垃圾數據做頻繁回收,影響ElasticSearch效率。

  生成環境中,bulk api常用。都是使用java代碼實現循環操作。一般一次bulk請求,執行一種操作。如:批量新增10000條數據等

四、ElasticSearch中的mapping

  Mapping在ElasticSearch中是非常重要的一個概念。決定了一個index中的field使用什麼數據格式存儲,使用什麼分詞器解析,是否有子字段等。

1,mapping的核心數據類型 

  • 文本(字符串):text
  • 整數:byte、short、integer、long
  • 浮點型:float、double
  • 布爾類型:boolean
  • 日期類型:date
  • 數組類型:array  {a:[]}
  • 對象類型:object  {a:{}}
  • 不分詞的字符串(關鍵字): keyword

2,dynamic mapping自動分配字段類型

  • true or false -> boolean
  • 123 -> long
  • 123.123 -> double
  • 2018-01-01 -> date
  • hello world -> text
  • [] -> array
  • {} -> object

  在上述的自動mapping字段類型分配的時候,只有text類型的字段需要分詞器。默認分詞器是standard分詞器。

3,查看索引mapping

  GET 索引名/_mapping 

{
  "my_index": { # 索引名
    "mappings": { # 映射列表
      "my_type": { # 類型名
        "properties": { # 字段列表
          "age": { # 字段名
            "type": "long" # 字段類型
          },
          "gender": { #字段名
            "type": "text", #字段類型
            "fields": { # 子字段列表
              "keyword": { # 子字段名
                "type": "keyword", # 子字段類型,keyword不進行分詞處理的文本類型。gender.keyword可以進行排序
                "ignore_above": 256 # 子字段存儲數據長度
              }
            }
          }
        }
      }
    }
  }
}

4,custom mapping

  可以通過命令,在創建index和type的時候來定製mapping映射,也就是指定字段的類型和字段數據使用的分詞器

  手工定製mapping時,只能新增mapping設置不能對已有的mapping進行修改

  如:有索引a,其中有類型b,增加字段f1的mapping定義。後續可以增加字段f2的mapping定義,但是不能修改f1字段的mapping定義。

a)創建索引時指定mapping

PUT 索引名稱
{
  "mappings":{
    "類型名稱":{
      "properties":{
        "字段名":{
          "type":類型,
          ["analyer":字段的分詞器,]
          ["fields":{
            "子字段名稱":{
              "type":類型,
              "ignore_above":長度限制
             }
           }]
         }
       }
     }
   }
}

例如:

PUT test_index
{
  "settings": {
    "number_of_shards": 2,
    "number_of_replicas": 1
  },
  "mappings": {
    "test_type":{
      "properties": {
        "author_id" : {
          "type": "byte",
          "index": false
        },
        "title" : {
          "type": "text",
          "analyzer": "ik_max_word",
          "fields": {
            "keyword" : {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        },
        "content" : {
          "type": "text",
          "analyzer": "ik_max_word"
        },
        "post_date" : {
          "type": "date"
        }
      }
    }
  }
}        
"index" - 是否可以作爲搜索索引。可選值:true | false
"analyzer" - 指定分詞器。
"type" - 指定字段類型

b)爲已有索引添加新的字段mapping

PUT 索引名/_mapping/類型名
{
  "properties":{
    "新字段名":{
      "type":類型,
      "analyer":字段的分詞器,
      "fields":{
        "子字段名":{
          "type":類型,
          "ignore_above":長度
        }
     }
   }
}    

例如:

PUT /test_index/_mapping/test_type
{
  "properties" : {
    "new_field" : { "type" : "text" , "analyzer" : "standard" }
  }
}

c)測試不同的字段分詞器

GET 索引名稱/_analyze
{
  "field":"索引中的text類型的字段名",
  "text":"要分詞處理的文本數據"
}

例如:

#測試content字段的分詞效果
GET test_index/_analyze { "field": "content", "text": "我是一個程序員" }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章