Elasticsearch入門
一.Elasticsearch介紹
Elasticsearch 是一個分佈式、可擴展、實時的搜索與數據分析引擎。 它能從項目一開始就賦予你的數據以搜索、分析和探索的能力,這是通常沒有預料到的。 它存在還因爲原始數據如果只是躺在磁盤裏面根本就毫無用處。
無論你是需要全文搜索,還是結構化數據的實時統計,或者兩者結合,這本指南都能幫助你瞭解其中最基本的概念, 從最基本的操作開始學習 Elasticsearch。之後,我們還會逐漸開始探索更加高級的搜索技術,不斷提升搜索體驗來滿足你的需求。
二.現有技術棧說明
在大多數應用中,多數實體或對象可以被序列化爲包含鍵值對的 JSON 對象。 一個 鍵 可以是一個字段或字段的名稱,一個 值 可以是一個字符串,一個數字,一個布爾值, 另一個對象,一些數組值,或一些其它特殊類型諸如表示日期的字符串,或代表一個地理位置的對象:
{
"name": "John Smith",
"age": 42,
"confirmed": true,
"join_date": "2014-06-01",
"home": {
"lat": 51.5,
"lon": 0.1
},
"accounts": [
{
"type": "facebook",
"id": "johnsmith"
},
{
"type": "twitter",
"id": "johnsmith"
}
]}
通常情況下,我們使用的術語 對象 和 文檔 是可以互相替換的。不過,有一個區別: 一個對象僅僅是類似於 hash 、 hashmap 、字典或者關聯數組的 JSON 對象,對象中也可以嵌套其他的對象。 對象可能包含了另外一些對象。在 Elasticsearch 中,術語 文檔 有着特定的含義。它是指最頂層或者根對象, 這個根對象被序列化成 JSON 並存儲到 Elasticsearch 中,指定了唯一 ID。
三.我們的架構方案分析
一個文檔不僅僅包含它的數據 ,也包含 元數據 —— 有關 文檔的信息。 三個必須的元數據元素如下:
-
_index
-
文檔在哪存放
-
_type
-
文檔表示的對象類別
-
_id
-
文檔唯一標識
_index
一個 索引 應該是因共同的特性被分組到一起的文檔集合。 例如,你可能存儲所有的產品在索引 products 中,而存儲所有銷售的交易到索引 sales 中。 雖然也允許存儲不相關的數據到一個索引中,但這通常看作是一個反模式的做法。
實際上,在 Elasticsearch 中,我們的數據是被存儲和索引在 分片 中,而一個索引僅僅是邏輯上的命名空間, 這個命名空間由一個或者多個分片組合在一起。 然而,這是一個內部細節,我們的應用程序根本不應該關心分片,對於應用程序而言,只需知道文檔位於一個 索引 內。 Elasticsearch 會處理所有的細節。
我們將在 索引管理 介紹如何自行創建和管理索引,但現在我們將讓 Elasticsearch 幫我們創建索引。 所有需要我們做的就是選擇一個索引名,這個名字必須小寫,不能以下劃線開頭,不能包含逗號。我們用 website 作爲索引名舉例。
_type
數據可能在索引中只是鬆散的組合在一起,但是通常明確定義一些數據中的子分區是很有用的。 例如,所有的產品都放在一個索引中,但是你有許多不同的產品類別,比如 "electronics" 、 "kitchen" 和 "lawn-care"。
這些文檔共享一種相同的(或非常相似)的模式:他們有一個標題、描述、產品代碼和價格。他們只是正好屬於“產品”下的一些子類。
Elasticsearch 公開了一個稱爲 types (類型)的特性,它允許您在索引中對數據進行邏輯分區。不同 types 的文檔可能有不同的字段,但最好能夠非常相似。 我們將在 類型和映射 中更多的討論關於 types 的一些應用和限制。
一個 _type
命名可以是大寫或者小寫,但是不能以下劃線或者句號開頭,不應該包含逗號, 並且長度限制爲256個字符. 我們使用 blog 作爲類型名舉例。
_id
ID 是一個字符串,當它和 _index 以及 _type 組合就可以唯一確定 Elasticsearch 中的一個文檔。 當你創建一個新的文檔,要麼提供自己的 _id ,要麼讓 Elasticsearch 幫你生成。
四.索引文檔
通過使用 index
API ,文檔可以被 索引 —— 存儲和使文檔可被搜索。 但是首先,我們要確定文檔的位置。正如我們剛剛討論的,一個文檔的 _index
、 _type
和 _id
唯一標識一個文檔。 我們可以提供自定義的 _id
值,或者讓 index
API 自動生成。
使用自定義的 ID
如果你的文檔有一個自然的標識符 (例如,一個 user_account
字段或其他標識文檔的值),你應該使用如下方式的 index
API 並提供你自己 _id
:
PUT /{index}/{type}/{id}{
"field": "value",
...}
舉個例子,如果我們的索引稱爲 website
,類型稱爲 blog
,並且選擇 123
作爲 ID ,那麼索引請求應該是下面這樣:
PUT /website/blog/123{
"title": "My first blog entry",
"text": "Just trying this out...",
"date": "2014/01/01"}
Elasticsearch 響應體如下所示:
{
"_index": "website",
"_type": "blog",
"_id": "123",
"_version": 1,
"created": true}
該響應表明文檔已經成功創建,該索引包括 _index
、 _type
和 _id
元數據, 以及一個新元素: _version
。
在 Elasticsearch 中每個文檔都有一個版本號。當每次對文檔進行修改時(包括刪除), _version
的值會遞增。 在 處理衝突 中,我們討論了怎樣使用 _version
號碼確保你的應用程序中的一部分修改不會覆蓋另一部分所做的修改。
Autogenerating IDs
如果你的數據沒有自然的 ID, Elasticsearch 可以幫我們自動生成 ID 。 請求的結構調整爲: 不再使用 PUT 謂詞(“使用這個 URL 存儲這個文檔”), 而是使用 POST 謂詞(“存儲文檔在這個 URL 命名空間下”)。
現在該 URL 只需包含 _index
和 _type
:
POST /website/blog/{
"title": "My second blog entry",
"text": "Still trying this out...",
"date": "2014/01/01"}
除了 _id
是 Elasticsearch 自動生成的,響應的其他部分和前面的類似:
{
"_index": "website",
"_type": "blog",
"_id": "AVFgSgVHUP18jI2wRx0w",
"_version": 1,
"created": true}
自動生成的 ID 是 URL-safe、 基於 Base64 編碼且長度爲20個字符的 GUID 字符串。 這些 GUID 字符串由可修改的 FlakeID 模式生成,這種模式允許多個節點並行生成唯一 ID ,且互相之間的衝突概率幾乎爲零。
取回一個文檔
爲了從 Elasticsearch 中檢索出文檔,我們仍然使用相同的 _index
, _type
, 和 _id
,但是 HTTP 謂詞更改爲 GET
:
GET /website/blog/123?pretty
響應體包括目前已經熟悉了的元數據元素,再加上 _source
字段,這個字段包含我們索引數據時發送給 Elasticsearch 的原始 JSON 文檔:
{
"_index" : "website",
"_type" : "blog",
"_id" : "123",
"_version" : 1,
"found" : true,
"_source" : {
"title": "My first blog entry",
"text": "Just trying this out...",
"date": "2014/01/01"
}}
在請求的查詢串參數中加上 pretty
參數,正如前面的例子中看到的,這將會調用 Elasticsearch 的 pretty-print 功能,該功能 使得 JSON 響應體更加可讀。但是, _source
字段不能被格式化打印出來。相反,我們得到的 _source
字段中的 JSON 串,剛好是和我們傳給它的一樣。
GET
請求的響應體包括 {"found": true}
,這證實了文檔已經被找到。 如果我們請求一個不存在的文檔,我們仍舊會得到一個 JSON 響應體,但是 found
將會是 false
。 此外, HTTP 響應碼將會是 404 Not Found
,而不是 200 OK
。
我們可以通過傳遞 -i
參數給 curl
命令,該參數能夠顯示響應的頭部:
curl -i -XGET http://localhost:9200/website/blog/124?pretty
顯示響應頭部的響應體現在類似這樣:
HTTP/1.1 404 Not FoundContent-Type: application/json; charset=UTF-8Content-Length: 83{
"_index" : "website",
"_type" : "blog",
"_id" : "124",
"found" : false}
返回文檔的一部分
默認情況下, GET
請求會返回整個文檔,這個文檔正如存儲在 _source
字段中的一樣。但是也許你只對其中的 title
字段感興趣。單個字段能用 _source
參數請求得到,多個字段也能使用逗號分隔的列表來指定。
GET /website/blog/123?_source=title,text
該 _source
字段現在包含的只是我們請求的那些字段,並且已經將 date
字段過濾掉了。
{
"_index" : "website",
"_type" : "blog",
"_id" : "123",
"_version" : 1,
"found" : true,
"_source" : {
"title": "My first blog entry" ,
"text": "Just trying this out..."
}}
或者,如果你只想得到 _source
字段,不需要任何元數據,你能使用 _source
端點:
GET /website/blog/123/_source
那麼返回的的內容如下所示:
{
"title": "My first blog entry",
"text": "Just trying this out...",
"date": "2014/01/01"}
檢查文檔是否存在
如果只想檢查一個文檔是否存在--根本不想關心內容—那麼用 HEAD
方法來代替 GET
方法。 HEAD
請求沒有返回體,只返回一個 HTTP 請求報頭:
curl -i -XHEAD http://localhost:9200/website/blog/123
如果文檔存在, Elasticsearch 將返回一個 200 ok
的狀態碼:
HTTP/1.1 200 OKContent-Type: text/plain; charset=UTF-8Content-Length: 0
若文檔不存在, Elasticsearch 將返回一個 404 Not Found
的狀態碼:
curl -i -XHEAD http://localhost:9200/website/blog/124
HTTP/1.1 404 Not FoundContent-Type: text/plain; charset=UTF-8Content-Length: 0
當然,一個文檔僅僅是在檢查的時候不存在,並不意味着一毫秒之後它也不存在:也許同時正好另一個進程就創建了該文檔。
更新整個文檔
在 Elasticsearch 中文檔是 不可改變 的,不能修改它們。相反,如果想要更新現有的文檔,需要 重建索引 或者進行替換, 我們可以使用相同的 index
API 進行實現,在 索引文檔 中已經進行了討論。
PUT /website/blog/123{
"title": "My first blog entry",
"text": "I am starting to get the hang of this...",
"date": "2014/01/02"}
在響應體中,我們能看到 Elasticsearch 已經增加了 _version
字段值:
{
"_index" : "website",
"_type" : "blog",
"_id" : "123",
"_version" : 2,
"created": false }
|
在內部,Elasticsearch 已將舊文檔標記爲已刪除,並增加一個全新的文檔。 儘管你不能再對舊版本的文檔進行訪問,但它並不會立即消失。當繼續索引更多的數據,Elasticsearch 會在後臺清理這些已刪除文檔。
-
從舊文檔構建 JSON
-
更改該 JSON
-
刪除舊文檔
-
索引一個新文檔
唯一的區別在於, update
API 僅僅通過一個客戶端請求來實現這些步驟,而不需要單獨的 get
和 index
請求。
如若大家覺得感興趣,請關注我的公衆號,後續文章都會在公衆號首發
關注我們吧