Elasticsearch - 快速入門


Elasticsearch是基於Apache 2.0開源的實時、分布式、分析搜索引擎,相比Lucene,Elasticsearch的上手比較容易,這篇文章主要紀錄Elasticsearch的基本概念和基本API。

官方對Elasticsearch的定義:

Elasticsearch is a distributed, RESTful search and analytics engine capable of solving a growing number of use cases. As the heart of the Elastic Stack, it centrally stores your data so you can discover the expected and uncover the unexpected.


你可能已經在Elasticsearch的文檔中看過如下詞匯:

  • NRT: 近實時(Near Realtime),當一個文檔保存至index,短暫的延遲后就可以被搜索。
  • Node: 指單個實例,存儲文檔並參與所在集群的索引和搜索,一台機器可以運行多個實例,每個實例啟動時都有自己的唯一標識。
  • Cluster: 指多個實例組成的集群,集群中的節點有相同的cluster.name(默認為"elasticsearch"),用戶可以通過集群對多個節點的所有數據進行索引和搜索。
  • Index: 索引在Elasticsearch中有兩種含義。作為名詞,索引可以指文檔的集合,作為動詞,可以說"對某個文檔進行索引",也就是把文檔存儲到索引。一個index的名稱即為其標識,名稱必須為小寫。如果和RDBMS相比的話,index的概念可能和database比較相似。
  • Type: 用於對同一個index中的數據進行邏輯分類。例如,有個存儲了sns數據的index,這個index中可能存在多個類型,例如用戶資料數據、評論數據、聊天數據...
  • Document: 文檔以JSON格式存儲,文檔中包含多個字段,每個文檔都有自己的類型並存儲於index中。
  • Shards: index可以切分成多個shard,每個shard分布到不同的節點上。通過shard可以在存儲還是搜索上緩解單個節點的壓力。
  • Replicas: 對shard進行復制,通過副本不僅保證了可用性,也提高了搜索效率。

一個index可以分為多個shard,默認配置下,每個index有5個primary shards和1個副本(也就是5個replica shards),也就是說這個index有10個shards。


為了進一步說明,這里簡單說明一下安裝過程。
首先需要確認機器上是否已經安裝了Java,這里建議使用java 8:

java -version
echo $JAVA_HOME


根據自己需要,可以選擇使用apt-getyum進行安裝,或者直接運行docker容器(docker.elastic.co/elasticsearch/elasticsearch:5.3.1), 參考https://www.elastic.co/guide/en/elasticsearch/reference/current/install-elasticsearch.html
這里我們用TAR包進行安裝

cd
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.2.1.tar.gz
cp elasticsearch-5.2.1.tar.gz /usr/local ; cd $_
tar xzvf elasticsearch-5.2.1.tar.gz


啟動時可以指定集群名稱和節點名稱:

elasticsearch-5.2.1/bin/elasticsearch -Ecluster.name=cluster0 -Enode.name=node0


Elasticsearch的web接口的默認端口為9200,或者可以根據自己的情況,在bin/elasticsearch.yml中對http.port進行修改。
最后查看響應結果,參考:

$ curl http://localhost:9200/
{
  "name" : "F16Po5W",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "gDEP8ViaSVuQkCADjMkWHg",
  "version" : {
    "number" : "5.2.1",
    "build_hash" : "db0d481",
    "build_date" : "2017-02-09T22:05:32.386Z",
    "build_snapshot" : false,
    "lucene_version" : "6.4.1"
  },
  "tagline" : "You Know, for Search"
}


下面檢查一下集群的狀態,參考:

$ curl http://localhost:9200/_cat/health?v
epoch      timestamp cluster  status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
1488018007 12:00:00  cluster0 green           1         1      0   0    0    0        0             0                  -                100.0%

輸出顯示,名為"elasticsearch"的狀態為"green",狀態分三種,green(健康)、yellow(服務可用,尚未分配副本)、red(不可用)。
red也並不是完全不可用,部分功能還是可以用的,例如搜索請求還是可以在部分shards中進行。

上面用到的_cat API,可以參考https://www.elastic.co/guide/en/elasticsearch/reference/current/cat.html,參數v代表verbose。

如果需要JSON格式,則去掉_cat即可,參考:

curl http://localhost:9200/_cluster/health?pretty


health只反映集群的大體情況,更詳細的信息,比如版本、節點、metadata等可以通過state獲得:

curl http://localhost:9200/_cluster/state?pretty


另外,還有一個stats,和state不同的是,stats返回的是和性能相關的信息,比如各項字節數、OS、fs、jvm等。
類似地,檢查節點狀態:

$ curl http://localhost:9200/_cat/nodes?v
ip        heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
127.0.0.1            7          90   5    0.00    0.01     0.05 mdi       *      node0


由於啟動時指定了節點名稱,這里節點的名稱為node0。
檢查index狀態:

$ curl http://localhost:9200/_cat/indices?v
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size


注意不是index的復數為indices,由於尚未創建任何index,這里沒有輸出。
但這並不妨礙試試analyze:

curl -X POST http://localhost:9200/_analyze?pretty -d '{"analyzer" : "standard", "text" : "Kavlez.Kim@gmail.com"}'


下面開始是Elasticsearch各個單位的基本API使用介紹。


Index

接下來創建一個index,注意不是POST,是PUT,參考:

$ curl -X PUT http://localhost:9200/province?pretty
{
  "acknowledged" : true,
  "shards_acknowledged" : true
}


重新確認下index狀態:

$ curl http://localhost:9200/_cat/indices?v
health status index    uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   province Ks7940k5QYKp9t7AEntbBA   5   1          0            0       650b           650b


如之前所說,默認有5個primary shards和1個replicas,盡管還沒有任何文檔。
第一個字段,健康狀態顯示為yellow,這是因為尚未分配副本,而我們只有一個節點。

創建index時也可以指定其他屬性,比如:

curl -X PUT -d '
{
   "settings" : {
      "number_of_shards" : 3
   },
   "mappings" : {
      "type1" : {
         "_source" : { "enabled" : false }, "properties" : {
            "name" : { "type" : "string" }, "code" : {"type":"string"}
         }
      }
   },
   "aliases" : {
      "alias_1" : {
         "filter" : {
            "term" : {"subdivision" : "Municipality" }
         }
      }
   }
}' http://localhost:9200/province 


至於GET,不只是用於察看index:

curl http://localhost:9200/province
curl http://localhost:9200/province/_settings
curl http://localhost:9200/province/_stats
curl http://localhost:9200/province/_flush
curl http://localhost:9200/province/_refresh

刪除一個index可以通過DELETE,如果並不打算刪除index,但又希望無法訪問該index,此時可以close
可以通過POST /{index}/_close/{index}/_open對index進行開關,當用戶訪問已關閉的index時會提示錯誤。

也可以通過_all或通配符對所有的index批量操作,但考慮到風險,可以通過在配置文件修改action.destructive_requires_name項禁用批量指定。

已關閉的index也會消耗一定的磁盤空間,開關操作可以通過cluster.indices.close.enable項禁用,該項默認為true

Document

文檔相關操作,先在province index中添加兩個文檔:

$ curl -X PUT -d '{"name": "Hong Kong", "code": "CN-91", "native": "香港"}' http://localhost:9200/province/special/1?pretty
{
  "_index" : "province",
  "_type" : "special",
  "_id" : "1",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "created" : true
}

$ curl -X PUT -d  '{"name": "Beijing", "code": "CN-11", "native": "北京"}' http://localhost:9200/province/municipality/1?pretty
{
  "_index" : "province",
  "_type" : "municipality",
  "_id" : "1",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "created" : true
}


請求中的specialmunicipality指的就是文檔的類型,盡管兩個文檔在同一個index,但類型不同。
后面的1就是文檔的id,可以對特定的index/type/id重新PUT,如果用同一個id提交多次,每次提交時_version會自動+1。
如果希望指定操作類型,則加上op_type參數,例如下面的例子會觸發versionconflictengine_exception,而不是version+1:

curl -X PUT -d '{"name": "Hong Kong", "code": "CN-91", "native": "香港"}' http://localhost:9200/province/special/1?op_type=create


如果希望添加文檔時自動生成id,則使用POST,此時就不能指定op_type了。

添加操作時不小心寫錯了index的名稱,但還是成功了,列出indices(GET _cat/indices)發現有幾個寫錯名稱的index。
Elasticsearch默認允許向不存在的index添加文檔,不存在則自動創建,該設置可以通過action.autocreateindex項進行修改,比如:

action.auto_create_index: +kav*,-da*

允許名稱以"kav"開頭的index自動創建,禁止以"da"開頭的。
如果想全部禁止,則設置-*


如果我想在已有的文檔中添加字段,相比重新將整個文檔重新PUT,不如用腳本進行更新,參考:

$ curl -X POST http://localhost:9200/province/special/1/_update -d '
{
   "script":{
      "inline": "ctx._source.dc = params.dial_code", "params":{
         "dial_code": 852
      }
   }
}'
{"_index":"province","_type":"special","_id":"1","_version":5,"result":"updated","_shards":{"total":2,"successful":1,"failed":0}}


至於GET,基本用法如下:

$ curl  http://10.69.201.47:9200/province/special/1?pretty
{
  "_index" : "province",
  "_type" : "special",
  "_id" : "1",
  "_version" : 1,
  "found" : true,
  "_source" : {
    "name" : "Hong Kong",
    "code" : "CN-91",
    "native" : "香港"
  }
}


另外,可以用_source進行過濾

$ curl  http://localhost:9200/province/special/1/_source=name,code?pretty
{
  "_index" : "province",
  "_type" : "special",
  "_id" : "1",
  "_version" : 1,
  "found" : true,
  "_source" : {
    "name" : "Hong Kong",
    "code" : "CN-91"
  }
}


如果想一次請求多個文檔,可以使用_mget,參考:

curl -X POST http://localhost:9200/_mget -d '
{
   "docs":[
      {
         "_index":"province", "_type": "special", "_id": "1"
      },
      {
         "_index":"province", "_type":"municipality", "_id": "1"
      }
   ]
}'


docs數組的第二項並不存在,於是返回{"_index" : "province", "_type" : "municipality", "_id" : "1", "found" : false }

刪除文檔用DELETE方法,刪除時可以加上其他參數,例如:

$ curl -X delete  http://localhost:9200/province/special/1?version=1
{
    "_index": "province",
    "_type": "special",
    "_id": "1",
    "_version": 1,
    "found": true,
    "_source": {
        "name": "Hong Kong",
        "code": "CN-91",
        "native": "香港"
    }
}

 

Search

search API提供兩種方式:

  • URI Search: GET的URL后面帶上query string
  • Request Body Search: 也就是將Query DSL作為body請求


至於搜索的對象,可以是多個index,也可以是某個index下的多個type。
search API默認為跨多個index和type,搜索的范圍需要在請求時指定。

對多個index,比如

curl http://localhost:9200/province,country/_search?q=name:Hong*

對多個type,比如

curl http://localhost:9200/province/special,municipality/_search?q=name:Shang*


下面是GET搜索時用到的一些常見的參數

Name Description
q 基本的query string,例如q=name:Hong*
df 即default field
analyzer 指定要使用的analyzer
analyze_wildcard 是否對通配符進行分析,默認為false
default_operator 可選值為AND和OR,默認為OR
lenient true時忽略數據格式警告,默認為false
_source 改項為false時結果將不包含文檔內容, 也可以通過sourceinclude & sourceexclude對返回字段進行篩選(逗號分隔)
stored_fields 對返回字段進行篩選(逗號分割)
sort 指定排序策略,格式為 fieldName:asc/fieldName:desc
timeout 超時時長
from 響應結果起始索引,默認為0
size 響應結果數,默認為10
search_type 可以為dfsquerythenfetch或者querythen_fetch,默認為后者


URL參數難以表述復雜的搜索,Elasticsearch提供了基於JSON格式的Query DSL來進行搜索。
雖然Query DSL提供了豐富的查詢類型,但就整體而言,提供不外乎兩種:

  • leaf query: 例如match,term,range,也就是匹配特定字段的特定值
  • compound query: 將其它leaf聚合到一起或者多個查詢聚合到一起。

由於DSL相關的內容過多,這里只簡單列舉幾種常用用法以作參考。

  • match all: match_all用於返回所有score為1.0內容

    $ curl -X post http://10.69.201.47:9200/province/_search -d '{
       "query":{
          "match_all":{}
       }
    }'
  • match: 根據字段和值的匹配進行搜索

    $ curl -X post http://10.69.201.47:9200/province/_search -d '{
       "query":{
          "match":{
                "name":"Hong Kong"
          }
       }
    }'
  • multi match: 用多個字段進行匹配,比如下面的例子中"CN-91"是香港的code,而這里卻用name和native字段進行搜索,因此沒有結果

    curl -X post http://10.69.201.47:9200/province/_search -d '{
       "query":{
         "multi_match":{
               "query":"CN-91",
               "fields":["name","native"]
         }
       }
    }'
  • query string: 如果我想multi match所有字段呢? 可以用query string

    curl -X post http://10.69.201.47:9200/province/_search -d '
    {
       "query":{
          "query_string":{
             "query":"Hong"
          }
       }
    }'
  • term: term搜索屬於低級(low-level)搜索,也就是直接查詢倒排索引(inverted index),而不經過分析過程。 在倒排索引中不存在則無結果。 下面的例子中,用"Hong"來搜索是沒有結果的,需要用"hong"

    curl -X post http://10.69.201.47:9200/province/_search -d '
    {
       "query":{
          "term":{"name":"hong"}
       }
    }
    '
  • range: 也屬於term搜索的一種,根據比較來限制值的范圍,支持的操作有gte,gt,lte,lt,例如

    curl -X POST http://10.69.201.47:9200/province/_search -d '{
       "query":{
          "range":{
             "code":{
                "gt":100
             }
          }
       }
    }'
  • type: 搜索對應type的文檔,屬於term level,因此type要嚴格匹配,例如

    curl -X POST http://10.69.201.47:9200/province/_search -d '{
       "query":{
          "type":{
             "value":"special"
          }
       }
    }'

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM