應用中的對象不多隻是簡單的鍵值列表,更多時候它擁有複雜的數據結構,好比包含日期、地理位置、另外一個對象或者數組。數據庫
總有一天你會想到把這些對象存儲到數據庫中。將這些數據保存到由行和列組成的關係數據庫中,就好像是把一個豐富,信息表現力強的對象拆散了放入一個很是大的表格中:你不得不拆散對象以適應表模式(一般一列表示一個字段),而後又不得不在查詢的時候重建它們。數組
Elasticsearch是面向文檔(document oriented)的,這意味着它能夠存儲整個對象或文檔(document)。然而它不只僅是存儲,還會索引(index)每一個文檔的內容使之能夠被搜索。在Elasticsearch中,你能夠對文檔(而非成行成列的數據)進行索引、搜索、排序、過濾。這種理解數據的方式與以往徹底不一樣,這也是Elasticsearch可以執行復雜的全文搜索的緣由之一。數據結構
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
咱們首先要作的是存儲員工數據,每一個文檔表明一個員工。在Elasticsearch中存儲數據的行爲就叫作索引(indexing),不過在索引以前,咱們須要明確數據應該存儲在哪裏。
在Elasticsearch中,文檔歸屬於一種類型(type),而這些類型存在於索引(index)中,咱們能夠畫一些簡單的對比圖來類比傳統關係型數據庫:
Relational DB -> Databases -> Tables -> Rows -> Columns
Elasticsearch -> Indices -> Types -> Documents -> Fields
Elasticsearch集羣能夠包含多個索引(indices)(數據庫),每個索引能夠包含多個類型(types)(表),每個類型包含多個文檔(documents)(行),而後每一個文檔包含多個字段(Fields)(列)。
你可能已經注意到索引(index)這個詞在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"] } }] } }
查詢字符串搜索便於經過命令行完成特定(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> } } } } }
如今不要擔憂語法太多,咱們將會在之後詳細的討論。你只要知道咱們添加了一個過濾器(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" } } }