Elasticsearch 快速入門教程

面向文檔

應用中的對象不多隻是簡單的鍵值列表,更多時候它擁有複雜的數據結構,好比包含日期、地理位置、另外一個對象或者數組。數據庫

總有一天你會想到把這些對象存儲到數據庫中。將這些數據保存到由行和列組成的關係數據庫中,就好像是把一個豐富,信息表現力強的對象拆散了放入一個很是大的表格中:你不得不拆散對象以適應表模式(一般一列表示一個字段),而後又不得不在查詢的時候重建它們。數組

Elasticsearch是面向文檔(document oriented)的,這意味着它能夠存儲整個對象或文檔(document)。然而它不只僅是存儲,還會索引(index)每一個文檔的內容使之能夠被搜索。在Elasticsearch中,你能夠對文檔(而非成行成列的數據)進行索引、搜索、排序、過濾。這種理解數據的方式與以往徹底不一樣,這也是Elasticsearch可以執行復雜的全文搜索的緣由之一。數據結構

JSON

ELasticsearch使用Javascript對象符號(JavaScript Object Notation),也就是JSON,做爲文檔序列化格式。JSON如今已經被大多語言所支持,並且已經成爲NoSQL領域的標準格式。它簡潔、簡單且容易閱讀。ui

如下使用JSON文檔來表示一個用戶對象:spa

{
    "email": "john@smith.com",
    "first_name": "John",
    "last_name": "Smith",
    "info": {
        "bio": "Eco-warrior and defender of the weak",
        "age": 25,
        "interests": [ "dolphins", "whales" ]
  },
    "join_date": "2014/05/01"
}    

儘管原始的 user  對象很複雜,但它的結構和對象的含義已經被完整的體如今JSON中了,在Elasticsearch中將對象轉化爲JSON並作索引要比在表結構中作相同的事情簡單的多。命令行

開始第一步

咱們如今開始進行一個簡單教程,它涵蓋了一些基本的概念介紹,好比索引(indexing)、搜索(search)以及聚合(aggregations)。經過這個教程,咱們可讓你對Elasticsearch能作的事以及其易用程度有一個大體的感受。rest

咱們接下來將陸續介紹一些術語和基本的概念,但就算你沒有立刻徹底理解也沒有關係。咱們將在本書的各個章節中更加深刻的探討這些內容。code

因此,坐下來,開始以旋風般的速度來感覺Elasticsearch的能力吧!對象

讓咱們創建一個員工目錄

假設咱們恰好在Megacorp工做,這時人力資源部門出於某種目的須要讓咱們建立一個員工目錄,這個目錄用於促進人文關懷和用於實時協同工做,因此它有如下不一樣的需求:blog

  • 數據可以包含多個值的標籤、數字和純文本。
  • 檢索任何員工的全部信息。
  • 支持結構化搜索,例如查找30歲以上的員工。
  • 支持簡單的全文搜索和更復雜的短語(phrase)搜索
  • 高亮搜索結果中的關鍵字
  • 可以利用圖表管理分析這些數據

索引員工文檔

咱們首先要作的是存儲員工數據,每一個文檔表明一個員工。在Elasticsearch中存儲數據的行爲就叫作索引(indexing),不過在索引以前,咱們須要明確數據應該存儲在哪裏。

在Elasticsearch中,文檔歸屬於一種類型(type),而這些類型存在於索引(index)中,咱們能夠畫一些簡單的對比圖來類比傳統關係型數據庫:

Relational DB -> Databases -> Tables -> Rows -> Columns
Elasticsearch -> Indices   -> Types  -> Documents -> Fields

Elasticsearch集羣能夠包含多個索引(indices)(數據庫),每個索引能夠包含多個類型(types)(表),每個類型包含多個文檔(documents)(行),而後每一個文檔包含多個字段(Fields)(列)。

「索引」含義的區分

你可能已經注意到索引(index)這個詞在Elasticsearch中有着不一樣的含義,因此有必要在此作一下區分:

  • 索引(名詞) 如上文所述,一個索引(index)就像是傳統關係數據庫中的數據庫,它是相關文檔存儲的地方,index的複數是indices 或indexes。
  • 索引(動詞) 「索引一個文檔」表示把一個文檔存儲到索引(名詞)裏,以便它能夠被檢索或者查詢。這很像SQL中的 INSERT  關鍵字,差異是,若是文檔已經存在,新的文檔將覆蓋舊的文檔。
  • 倒排索引 傳統數據庫爲特定列增長一個索引,例如B-Tree索引來加速檢索。Elasticsearch和Lucene使用一種叫作倒排索引(inverted index)的數據結構來達到相同目的。

默認狀況下,文檔中的全部字段都會被索引(擁有一個倒排索引),只有這樣他們纔是可被搜索的。

咱們將會在倒排索引章節中更詳細的討論。

因此爲了建立員工目錄,咱們將進行以下操做:

  • 爲每一個員工的文檔(document)創建索引,每一個文檔包含了相應員工的全部信息。
  • 每一個文檔的類型爲 employee  。
  • employee  類型歸屬於索引 megacorp  。
  • megacorp  索引存儲在Elasticsearch集羣中。

實際上這些都是很容易的(儘管看起來有許多步驟)。咱們能經過一個命令執行完成的操做:

PUT /megacorp/employee/1
{
    "first_name" : "John",
    "last_name" : "Smith",
    "age" : 25,
    "about" : "I love to go rock climbing",
    "interests": [ "sports", "music" ]
}

咱們看到path: /megacorp/employee/1  包含三部分信息:

名字 說明
 megacorp  索引名
 employee  類型名
 1  這個員工的ID

請求實體(JSON文檔),包含了這個員工的全部信息。他的名字叫「John Smith」,25歲,喜歡攀巖。

很簡單吧!它不須要你作額外的管理操做,好比建立索引或者定義每一個字段的數據類型。咱們可以直接索引文檔,Elasticsearch已經內置全部的缺省設置,全部管理操做都是透明的。

接下來,讓咱們在目錄中加入更多員工信息:

PUT /megacorp/employee/2
{
    "first_name" : "Jane",
    "last_name" : "Smith",
    "age" : 32,
    "about" : "I like to collect rock albums",
    "interests": [ "music" ]
}

PUT /megacorp/employee/3
{
    "first_name" : "Douglas",
    "last_name" : "Fir",
    "age" : 35,
    "about": "I like to build cabinets",
    "interests": [ "forestry" ]
}

檢索文檔

如今Elasticsearch中已經存儲了一些數據,咱們能夠根據業務需求開始工做了。第一個需求是可以檢索單個員工的信息。

這對於Elasticsearch來講很是簡單。咱們只要執行HTTP GET請求並指出文檔的「地址」——索引、類型和ID既可。根據這三部分信息,咱們就能夠返回原始JSON文檔:

GET /megacorp/employee/1

響應的內容中包含一些文檔的元信息,John Smith的原始JSON文檔包含在 _source  字段中。

{
    "_index" : "megacorp",
    "_type" : "employee",
    "_id" : "1",
    "_version" : 1,
    "found" : true,
    "_source" : {
        "first_name" : "John",
        "last_name" : "Smith",
        "age" : 25,
        "about" : "I love to go rock climbing",
        "interests": [ "sports", "music" ]
    }
}

咱們經過HTTP方法 GET  來檢索文檔,一樣的,咱們可使用 DELETE  方法刪除文檔,使用 HEAD  方法檢查某文檔是否存在。若是想更新已存在的文檔,咱們只需再 PUT  一次。

簡單搜索

GET  請求很是簡單——你能輕鬆獲取你想要的文檔。讓咱們來進一步嘗試一些東西,好比簡單的搜索!

咱們嘗試一個最簡單的搜索所有員工的請求:

 

GET /megacorp/employee/_search

你能夠看到咱們依然使用 megacorp  索引和 employee  類型,可是咱們在結尾使用關鍵字 _search  來取代原來的文檔ID。響應內容的 hits  數組中包含了咱們全部的三個文檔。默認狀況下搜索會返回前10個結果。

{
    "took": 6,
    "timed_out": false,
    "_shards": {...
    },
    "hits": {
        "total": 3,
        "max_score": 1,
        "hits": [{
            "_index": "megacorp",
            "_type": "employee",
            "_id": "3",
            "_score": 1,
            "_source": {
                "first_name": "Douglas",
                "last_name": "Fir",
                "age": 35,
                "about": "I like to build cabinets",
                "interests": ["forestry"]
            }
        },
        {
            "_index": "megacorp",
            "_type": "employee",
            "_id": "1",
            "_score": 1,
            "_source": {
                "first_name": "John",
                "last_name": "Smith",
                "age": 25,
                "about": "I love to go rock climbing",
                "interests": ["sports", "music"]
            }
        },
        {
            "_index": "megacorp",
            "_type": "employee",
            "_id": "2",
            "_score": 1,
            "_source": {
                "first_name": "Jane",
                "last_name": "Smith",
                "age": 32,
                "about": "I like to collect rock albums",
                "interests": ["music"]
            }
        }]
    }
}

接下來,讓咱們搜索姓氏中包含「Smith」的員工。要作到這一點,咱們將在命令行中使用輕量級的搜索方法。這種方法常被稱做查詢字符串(query string)搜索,由於咱們像傳遞URL參數同樣去傳遞查詢語句:

GET /megacorp/employee/_search?q=last_name:Smith

咱們在請求中依舊使用 _search  關鍵字,而後將查詢語句傳遞給參數 q=  。這樣就能夠獲得全部姓氏爲Smith的結果:

{...
  "hits": { "total": 2, "max_score": 0.30685282, "hits": [
       {...
         "_source": {   "first_name": "John",   "last_name": "Smith",   "age": 25,   "about": "I love to go rock climbing",   "interests": ["sports", "music"]   }   },   {...
         "_source": {   "first_name": "Jane",   "last_name": "Smith",   "age": 32,   "about": "I like to collect rock albums",   "interests": ["music"]   }   }] } }

使用DSL語句查詢

查詢字符串搜索便於經過命令行完成特定(ad hoc)的搜索,可是它也有侷限性(參閱簡單搜索章節)。Elasticsearch提供豐富且靈活的查詢語言叫作DSL查詢(Query DSL),它容許你構建更加複雜、強大的查詢。

DSL(Domain Specific Language特定領域語言)以JSON請求體的形式出現。咱們能夠這樣表示以前關於「Smith」的查詢:

GET /megacorp/employee/_search
{
    "query" : {
        "match" : {
        "last_name" : "Smith"
        }
    }
}

這會返回與以前查詢相同的結果。你能夠看到有些東西改變了,咱們再也不使用查詢字符串(query string)作爲參數,而是使用請求體代替。這個請求體使用JSON表示,其中使用了 match  語句(查詢類型之一,具體咱們之後會學到)。

更復雜的搜索

咱們讓搜索稍微再變的複雜一些。咱們依舊想要找到姓氏爲「Smith」的員工,可是咱們只想獲得年齡大於30歲的員工。咱們的語句將添加過濾器(filter),它使得咱們高效率的執行一個結構化搜索:

GET /megacorp/employee/_search
{
    "query" : {
        "filtered" : {
            "filter" : {
                "range" : {
                    "age" : { "gt" : 30 }  <1>
                }
            },
            "query" : {
                "match" : {
                    "last_name" : "smith"  <2>
                }
            }
        }
    }
} 
  • <1> 這部分查詢屬於區間過濾器(range filter),它用於查找全部年齡大於30歲的數據—— gt  爲"greater than"的縮寫。
  • <2> 這部分查詢與以前的 match  語句(query)一致。

如今不要擔憂語法太多,咱們將會在之後詳細的討論。你只要知道咱們添加了一個過濾器(filter)用於執行區間搜索,而後重複利用了以前的 match  語句。如今咱們的搜索結果只顯示了一個32歲且名字是「Jane Smith」的員工:

{
  ...
  "hits": {
    "total": 1,
    "max_score": 0.30685282,
    "hits": [
      {
        ...
        "_source": {
          "first_name": "Jane",
          "last_name": "Smith",
          "age": 32,
          "about": "I like to collect rock albums",
          "interests": [ "music" ]
        }
      }
    ]   } }

全文搜索

到目前爲止搜索都很簡單:搜索特定的名字,經過年齡篩選。讓咱們嘗試一種更高級的搜索,全文搜索——一種傳統數據庫很難實現的功能。

咱們將會搜索全部喜歡「rock climbing」的員工:

GET /megacorp/employee/_search
{
  "query" : {
    "match" : {
      "about" : "rock climbing"
    }
  }
}

 

原文:https://es.xiaoleilu.com/

PDF:https://pan.baidu.com/s/1o8MbG7o

相關文章
相關標籤/搜索