1. 程式人生 > >實時搜尋引擎Elasticsearch(2)——Rest API的使用

實時搜尋引擎Elasticsearch(2)——Rest API的使用

上一篇文章簡單的介紹了ES的基本概念、安裝執行等內容,本文將介紹ES中的常用Rest API。

ES為開發者提供了非常豐富的基於HTTP協議的Rest API,只需要向ES服務端傳送簡單的Rest請求,就可以實現非常強大的功能。本篇文章主要介紹ES中常用操作的Rest API的使用,同時會講解ES的原始碼工程中的API介面文件,通過了解這個API文件的介面描述結構,就基本上可以實現ES中的絕大部分功能。

注意:查詢是ES的核心。作為一個先進的搜尋引擎,ES中提供了多種查詢介面。本篇僅僅會涉及查詢API的結構,而具體如何使用ES所提供的各種查詢API,會在接下來的博文中做詳細介紹。

基礎知識

如果之前沒有用過類似於ES這樣的索引資料庫(暫且將ES歸為資料庫類,與傳統的資料庫有較大的區別),要理解本篇博文介紹的API是有些難度的。本節先介紹一些基礎知識,對理解全文有很幫助。

Rest介紹

筆者在學習軟體開發過程中,多次聽到過Rest Http這個概念,但在很長的一段時間裡,死活搞不懂這玩意到底是個什麼東西。剛開始看相關資料時,看得雲裡霧裡,完全不知所云 _。這玩意太過於抽象和理論,心裡覺得有必要搞這麼複雜麼。隨著自己動手開發的東西越來越多,才開始對它有了一丟丟感覺。

Rest完全不是三言兩語就能將清楚的,它有自己的一套體系,所以筆者打算以後單獨寫一些有關Rest的博文。在這裡推薦一篇優秀的

文章,它對Rest講的相當清楚,本人看完之後真有醍醐灌頂的感覺!

Mapping詳解

Mapping是ES中的一個很重要的內容,它類似於傳統關係型資料中table的schema,用於定義一個索引(index)的某個型別(type)的資料的結構。

在傳統關係型資料庫,我們必須首先建立table並同時定義其schema,如下面的SQL語句。下面程式碼中小括號內的程式碼的作用就是定義person_info的schema(模式)。

create table person_info
(
    name varchar(20),
    age tinyint 
)
  • 1
  • 2
  • 3
  • 4
  • 5

在ES中,我們無需手動建立type(相當於table)和mapping(相關與schema)。在預設配置下,ES可以根據插入的資料自動地建立type及其mapping。在下面的API介紹部分中,會做相關的試驗。當然,在實際使用過程中我們可能就想硬性規定mapping,可以通過配置檔案關閉ES的自動建立mapping功能。具體配置方式見上一篇部落格

mapping中主要包括欄位名、欄位資料型別和欄位索引型別這3個方面的定義。

欄位名:這就不用說了,與傳統資料庫欄位名作用一樣,就是給欄位起個唯一的名字,好讓系統和使用者能識別。

欄位資料型別:定義該欄位儲存的資料的型別,不符合資料型別定義的資料不能儲存到ES中。下表列出的是ES中所支援的資料型別。(大類是對所有型別的一種歸類,小類是實際使用的型別。)

大類 包含的小類
String string
Whole number byte, short, integer, long
Floating point float, double
Boolean boolean
Date date

欄位索引型別:索引是ES中的核心,ES之所以能夠實現實時搜尋,完全歸功於Lucene這個優秀的Java開源索引。在傳統資料庫中,如果欄位上建立索引,我們仍然能夠以它作為查詢條件進行查詢,只不過查詢速度慢點。而在ES中,欄位如果不建立索引,則就不能以這個欄位作為查詢條件來搜尋。也就是說,不建立索引的欄位僅僅能起到資料載體的作用。string型別的資料肯定是日常使用得最多的資料型別,下面介紹mapping中string型別欄位可以配置的索引型別。

索引型別 解釋
analyzed 首先分析這個字串,然後再建立索引。換言之,以全文形式索引此欄位。
not_analyzed 索引這個欄位,使之可以被搜尋,但是索引內容和指定值一樣。不分析此欄位。
no 不索引這個欄位。這個欄位不能被搜尋到。

如果索引型別設定為analyzed,在表示ES會先對這個欄位進行分析(一般來說,就是自然語言中的分詞),ES內建了不少分析器(analyser),如果覺得它們對中文的支援不好,也可以使用第三方分析器。由於筆者在實際專案中僅僅將ES用作普通的資料查詢引擎,所以並沒有研究過這些分析器。如果將ES當做真正的搜尋引擎,那麼挑選正確的分析器是至關重要的。

mapping中除了上面介紹的3個主要的內容外,還有其他的定義內容,詳見官網文件

常用的Rest API介紹

下面介紹一下ES中的一些常用的Rest API。掌握了這些API的用法,基本上就可以簡單地使用ES了。

我們需要藉助能夠傳送HTTP請求的工具呼叫這些API,工具是可以任意的,包括網頁瀏覽器。這裡利用Linux上的curl命令來發送HTTP請求。基本的命令結構為:

  curl <-Xaction> url -d 'body'
  # 這裡的action表示HTTP協議中的各種動作,包括GET、POST、PUT、DELETE等。
  • 1
  • 2

注意。文中的示例程式碼裡面包含了使用者註釋的文字,就是 # 號後面的文字。執行程式碼時,請注意刪除這些註釋。

檢視叢集(Cluster)資訊相關API

(1)檢視叢集健康資訊。

  curl -XGET "192.168.1.101:9200/_cat/heath?v"
  • 1

返回結果為:

epoch      timestamp cluster       status node.total node.data shards pri relo init unassign pending_tasks 
1440206633 18:23:53  elasticsearch green           1         1      0   0    0    0        0             0 
  • 1
  • 2

返回結果的主要欄位意義:

  • cluster:叢集名,是在ES的配置檔案中配置的cluster.name的值。
  • status:叢集狀態。叢集共有green、yellow或red中的三種狀態。green代表一切正常(叢集功能齊全),yellow意味著所有的資料都是可用的,但是某些複製沒有被分配(叢集功能齊全),red則代表因為某些原因,某些資料不可用。如果是red狀態,則要引起高度注意,資料很有可能已經丟失。
  • node.total:叢集中的節點數。
  • node.data:叢集中的資料節點數。
  • shards:叢集中總的分片數量。
  • pri:主分片數量,英文全稱為private。
  • relo:複製分片總數。
  • unassign:未指定的分片數量,是應有分片數和現有的分片數的差值(包括主分片和複製分片)。

我們也可以在請求中新增help引數來檢視每個操作返回結果欄位的意義。

  curl -XGET "192.168.1.101:9200/_cat/heath?help"
  • 1

返回結果如下:

epoch         | t,time                                   | seconds since 1970-01-01 00:00:00  
timestamp     | ts,hms,hhmmss                            | time in HH:MM:SS                   
cluster       | cl                                       | cluster name                       
status        | st                                       | health status                      
node.total    | nt,nodeTotal                             | total number of nodes              
node.data     | nd,nodeData                              | number of nodes that can store data
shards        | t,sh,shards.total,shardsTotal            | total number of shards             
pri           | p,shards.primary,shardsPrimary           | number of primary shards           
relo          | r,shards.relocating,shardsRelocating     | number of relocating nodes         
init          | i,shards.initializing,shardsInitializing | number of initializing nodes       
unassign      | u,shards.unassigned,shardsUnassigned     | number of unassigned shards        
pending_tasks | pt,pendingTasks                          | number of pending tasks   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

確實是很好很強大。有了這個東東,就可以減少看文件的時間。ES中許多API都可以新增help引數來顯示欄位含義,哪些可以這麼做呢?每個API都試試就知道了。

當然,如果你覺得返回的東西太多,看著眼煩,我們也可以人為地指定返回的欄位。

  curl -XGET "192.168.1.101:9200/_cat/health?h=cluster,pri,relo&v"
  • 1

這次的返回結果就簡單很多羅。對於患有嚴重強迫症的患者來說,這是福音啊!

cluster       pri relo 
elasticsearch   0    0 
  • 1
  • 2

(2)檢視叢集中的節點資訊。

  curl -XGET "192.168.1.101:9200/_cat/nodes?v"
  • 1

返回節點的詳細資訊如下:

host          ip            heap.percent ram.percent load node.role master name    
master.hadoop 192.168.1.101            3          35 0.00 d         *      Ezekiel 
  • 1
  • 2

(3)檢視叢集中的索引資訊。

  curl -XGET "192.168.1.101:9200/_cat/indices?v"
  • 1

返回叢集中的索引資訊如下:

health status index      pri rep docs.count docs.deleted store.size pri.store.size 
yellow open   index_test   5   1          0            0       575b           575b 
  • 1
  • 2

更多的檢視和監視ES的API參見官網文件

索引(Index)相關API

(1)建立一個新的索引。

curl -XPUT "192.168.1.101:9200/index_test"
  • 1

如果返回下面的資訊,則說明索引建立成功。如果不是,則ES會返回相應的異常資訊。通常可以通過異常資訊的最後一項推斷出失敗的原因。

{
    "acknowledged": true
}
  • 1
  • 2
  • 3

上面的操作使用預設的配置資訊建立一個索引。大多數情況下,我們想在索引建立的時候就將我們所需的mapping和其他配置確定好。下面的操作就可以在建立索引的同時,建立settings和mapping。

curl -XPUT "192.168.1.101:9200/index_test" -d ' # 注意這裡的'號
{
  "settings": {
    "index": {
      "number_of_replicas": "1", # 設定複製數
      "number_of_shards": "5" # 設定主分片數
    }
  },
  "mappings": { # 建立mapping
    "test_type": { # 在index中建立一個新的type(相當於table)
      "properties": {
        "name": { # 建立一個欄位(string型別資料,使用普通索引)
          "type": "string",
          "index": "not_analyzed"
        },
        "age": {
          "type": "integer"
        }
      }
    }
  }
}'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

(2)刪除一個索引。

curl -XDELETE "192.168.1.101:9200/index_test"
  • 1

如果返回與建立索引同樣的資訊,則說明刪除成功。反之,則返回相應的異常資訊。更多的索引操作參見ES官網文件

對映(Mapping)相關API

(1)建立索引的mapping。

curl -XPUT 'localhost:9200/index_test/_mapping/test_type' -d ' 
{
  "test_type": { # 注意,這裡的test_type與url上的test_type名儲存一致
      "properties": {
        "name": {
          "type": "string",
          "index": "not_analyzed"
        },
        "age": {
          "type": "integer"
        }
      }
    }
  }'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

如果不想單獨建立mapping,可以使用上一節的方法(建立索引時建立mappings)。

假設我們的專案中有多個環境(開發環境、測試環境等),那每一個環境的mapping總要一致的吧,那每次建立一次mappings就比較麻煩了,而且還容易導致資料不一致。莫急,ES還給我們準備另外一種建立mapping的方式。可以按照下面的步驟來做。

步驟1 建立一個副檔名為test_type.json的檔名,其中type_test就是mapping所對應的type名。

步驟2 在test_type.json中輸入mapping資訊。假設你的mapping如下:

{
  "test_type": { # 注意,這裡的test_type與json檔名必須一致
      "properties": {
        "name": {
          "type": "string",
          "index": "not_analyzed"
        },
        "age": {
          "type": "integer"
        }
      }
    }
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

步驟3 在$ES_HOME/config/路徑下建立mappings/index_test子目錄,這裡的index_test目錄名必須與我們要建立的索引名一致。將test_type.json檔案拷貝到index_tes目錄下。

步驟4 建立index_test索引。操作如下:

curl -XPUT "192.168.1.101:9200/index_test" # 注意,這裡的索引名必須與mappings下新建的index_test目錄名一致
  • 1

這樣我們就建立了一個新的索引,並且使用了test_type.json所定義的mapping作為索引的mapping。就是這麼簡單方便!

(2)刪除mapping。

curl -XDELETE 'localhost:9200/index_test/_mapping/test_type'
  • 1

(3)檢視索引的mapping。

curl -XGET 'localhost:9200/index_test/_mapping/test_type'
  • 1

更多的mapping相關操作參加官網文件

文件(document)相關API

(1)新增一個文件。

curl -XPUT '192.168.1.101:9200/index_test/test_type/1?pretty' -d ' # 這裡的pretty引數的作用是使得返回的json顯示地更加好看。1是文件的id值(唯一鍵)。
{
    "name": "zhangsan",
    "age" : "12"
}'
  • 1
  • 2
  • 3
  • 4
  • 5

(2)更新一個文件

curl -XPOST '192.168.1.101:9200/index_test/test_type/1?pretty' -d ' # 這裡的1必須是索引中已經存在id,否則就會變成新增文件操作
{
    "name": "lisi",
    "age" : "12"
}'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

(3)刪除一個文件

curl -XDELETE '192.168.1.101:9200/index_test/test_type/1?pretty' # 這裡的1必須是索引中已經存在id
  • 1

(4)查詢單個文件

curl -XGET '192.168.1.101:9200/index_test/test_type/1?pretty'
  • 1

上面的操作僅僅查詢id為1的一條文件,這樣看似乎ES的查詢也太弱了。前面已經說過了,查詢操作是ES中的核心,是其立身的根本。但是本文的重點並不在這裡,為了防止文章的篇幅過長,之後將專本介紹ES中的查詢操作。

原始碼中提供的Rest API文件結構

ES的原始碼託管在Github上。將原始碼下載下來之後,裡面有一個資料夾專門存放ES中絕大部分的Rest API。有了這些文件,就不必每次都要到官網上查詢介面文件了(PS:ES的官網真的很慢)。  下面以cat.health.json檔案為例簡單地介紹這些Rest API文件的結構。一旦結構搞清楚了,文件看起來就比較順心,ES用起來就更加得心應手了!

{
  "cat.health": {
    "documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/master/cat-health.html", # 該文件對應的官方站點
    "methods": ["GET"], 
    "url": { # url部分可選
      "path": "/_cat/health",  
      "paths": ["/_cat/health"],
      "parts": {
      },
      "params": {
        "local": {
          "type" : "boolean",
          "description" : "Return local information, do not retrieve the state from master node (default: false)"
        },
        "master_timeout": {
          "type" : "time",
          "description" : "Explicit operation timeout for connection to master node"
        },
        "h": {
            "type": "list",
            "description" : "Comma-separated list of column names to display"
        },
        "help": {
          "type": "boolean",
          "description": "Return help information",
          "default": false
        },
        "ts": {
          "type": "boolean",
          "description": "Set to false to disable timestamping",
          "default": true
        },
        "v": {
          "type": "boolean",
          "description": "Verbose mode. Display column headers",
          "default": true
        }
      }
    },
    "body": null
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

上面文件介面所對應的Reqeust操作如下:

curl -XGET "localhost:9200/_cat/health?v" -d 'body'
  • 1

該操作命令可劃分為5個部分,下面把這5個部分與文件對應起來。通過這個例子,就可以在閱讀其他文件後,使用正確的操作了。

  1. 第1部分(-XGET):對應文件中methods所包含的GET操作。
  2. 第2部分(localhost:9200):是ES服務端所在主機的hostname和port。
  3. 第3部分(/_cat/health):對應文件中的url。其中path是最簡單的url;paths是除了path之外的其他url;parts描述和解釋paths裡面的url的可變部分(通常用{}包裹,如{index})。
  4. 第4部分v:表示引數,對應文件中的params。像“v”這種boolean型別的引數,不需要特意指定其布林值(true或者false),出現即表示true,否則為false。
  5. 第5部分body:表示要傳遞的資料主體,對應文件中的body。如果body裡面指明“required=true”,則表示必須傳入body資料。具體body裡面需要傳怎樣的資料,則可以訪問文件中的documentation欄位所指明的官方站點進行查詢。

總結

本文重點介紹了ES中的一些常用Rest API的用法,並在開始部分簡單地介紹了一些基礎知識(Rest和mapping)。掌握了這些API的呼叫,就可以利用ES完成簡單的應用程式了。當然,ES的API遠不止這些,如果想要更加深入地瞭解ES的使用及其內部原理,建議先仔細地閱讀ES的官網文件。然後下載其原始碼進行研究。

下一篇文章將介紹ES中查詢和聚合API。由於本人在實際專案中僅僅把ES當做索引資料庫,而且鑑於本人的搜尋引擎的知識有限,所以僅僅會介紹ES的基本查詢功能。