想要知道ElasticSearch是如何使用的,最快的方式就是通過一個簡單的例子,第一個例子將會包括基本概念如索引、搜索、和聚合等,需求是關於公司管理員工的一些業務。
員工文檔索引
業務首先需要存儲員工數據。這將采取一個員工文檔的形式:單個文檔表示單個員工。在Elasticsearch中存儲數據的行為稱為索引,但是在索引文檔之前,我們需要決定在哪里存儲它。
在Elasticsearch中,文檔屬於某個類型,這些類型位於索引中。可以繪制一些(粗略)與傳統關系數據庫的對比:
Relational DB ⇒ Databases ⇒ Tables ⇒ Rows ⇒ Columns
Elasticsearch ⇒ Indices ⇒ Types ⇒ Documents ⇒ Fields
Elasticsearch集群可以包含多個索引(數據庫),這些索引又包含多個類型(表)。這些類型包含多個文檔(行),每個文檔都有多個字段(列)。
您可能已經注意到,在Elasticsearch的上下文中,索引被重載了幾個含義。如下:
- 索引(名詞):正如前面所解釋的那樣,索引就像傳統的關系數據庫中的數據庫一樣。它是存儲相關文檔的地方。index的復數形式是indices或indexes。
- 索引(動詞):索引一個文檔是將一個文檔存儲在索引(名詞)中,以便它可以檢索和查詢。它很像插入關鍵詞SQL。此外,如果文檔已經存在,新的文檔將取代舊的。
- 倒排索引:關系數據庫中增加一個索引,如B-樹索引,對特定列為了提高數據檢索的速度。Elasticsearch和Lucene提供相同目的的索引稱為倒排索引。
默認情況下,文檔中的每個字段索引(有一個倒排索引)這樣的搜索。一個沒有倒排索引字段不可搜索。
因此我們的員工目錄,我們需要處理如下事情:
- 索引的每個文檔,包含每個員工的所有細節。
- 每個文檔都屬於
employee類型。 - 類型都包含在
megacop索引中。 - 該索引將駐留我們Elasticsearch集群內。
下面通過命令去索引第一個員工:
PUT /megacorp/employee/1
{
"first_name" : "John",
"last_name" : "Smith",
"age" : 25,
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
}
注意/megacorp/employee/1包含的信息。
megacorp:索引的名稱
emplogee:類型的名稱
1:員工的id
成功執行返回的是一個JSON文本,包含所有關於該員工的信息。
注意:
- 如果執行過程中失敗了,可能存在的原因是elasticsearch默認配置中不允許自動創建索引,所以我們可以先簡單在elasticsearch.yml配置文件添加
action.auto_create_index:true,允許自動創建索引。 - 沒有必要首先執行任何管理任務,如創建一個索引或指定每個字段所包含的數據類型。我們可以直接索引一個文檔。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文檔,並且響應包含有關文檔的一些元數據,以及Douglas Fir的原始JSON文檔作為_source字段:

可以查看:ElasticSearch 5學習(4)——簡單搜索筆記
以同樣的方式,我們將HTTP動詞從PUT更改為GET以便檢索文檔,我們可以使用DELETE動詞刪除文檔,並使用HEAD動詞檢查文檔是否存在。要用更新的版本替換現有文檔,我們只需再次PUT。
GET很簡單,可以得到要求的文件。嘗試一些更高級的東西,我們可以搜索所有員工,請求:
GET /megacorp/employee/_search
您可以看到我們仍在使用索引megacorp和類型employee,但是我們現在使用_search端點,而不是指定文檔ID。響應包括我們在hits數組中的所有三個文檔。默認情況下,搜索將返回前10個結果。
響應不僅告訴我們哪些文檔匹配,而且還包括整個文檔本身,以便向用戶顯示搜索結果的所有信息。
接下來,讓我們嘗試搜索在其姓氏中有“Smith”的員工。為此,我們將使用一個輕松的搜索方法,它很容易從命令行使用。此方法通常稱為查詢字符串搜索,因為我們將搜索作為URL查詢字符串參數傳遞:

DSL查詢
查詢字符串搜索對於從命令行進行搜索非常方便,但它有其局限性。Elasticsearch提供了一種豐富,靈活的查詢語言,稱為查詢DSL,它允許我們構建更復雜,更健壯的查詢。
使用JSON請求正文指定域特定語言(DSL)。我們可以代表所有以前的搜索,像這樣:
GET /megacorp/employee/_search
{
"query" : {
"match" : {
"last_name" : "Smith"
}
}
}
這將返回與上一個查詢相同的結果。可以看到一些事情已經改變。例如,我們不再使用查詢字符串參數,而是使用請求正文。此請求體是使用JSON構建的,並使用匹配查詢。
讓我們讓搜索更復雜一點。我們仍然希望找到所有名字為Smith的員工,但我們只想要30歲以上的員工。我們的查詢將稍微改變一點,以容納一個過濾器,這使我們能夠有效地執行結構化搜索:
GET /megacorp/employee/_search
{
"query" : {
"bool" : {
"must" : {
"match" : {
"last_name" : "smith"
}
},
"filter" : {
"range" : {
"age" : { "gt" : 30 }
}
}
}
}
}
我們添加了一個過濾器,執行范圍搜索,並重復使用與以前相同的匹配查詢。
現在我們的結果顯示只有一個員工剛好是32並被命名為smith:

注意:關於過濾器在Elasticsearch2.0開始有很大的更新,所以有些過濾操作可能會報錯。例如:filtered query已經被廢棄。
全文搜索(Full-Text Search)
到目前為止的搜索很簡單:單個名字,按年齡過濾。讓我們嘗試更高級的全文搜索,傳統數據庫真正難以勝任的任務。
我們將尋找所有喜歡攀岩的員工:
GET /megacorp/employee/_search
{
"query" : {
"match" : {
"about" : "rock climbing"
}
}
}
您可以看到我們使用與之前相同的匹配查詢來搜索關於“攀岩”字段。我們得到兩個匹配的文檔:

默認情況下,Elasticsearch按匹配結果的相關性分值(即每個文檔與查詢匹配程度)對匹配結果進行排序。第一個和最高分的結果是顯而易見的:John·Smith關於字段清楚地說“攀岩”。
但為什么Jane·Smith也返回了?她的文檔被返回的原因是因為在她的字段中提到了“rock”這個詞。因為只有“岩石”被提及,而不是“攀登”,她的分數低於John的。
這是Elasticsearch如何在全文字段中進行搜索並返回最相關的結果的一個很好的例子。這種相關性的概念對於Elasticsearch很重要,並且是一個完全與傳統關系數據庫無關的概念,其中記錄匹配或不匹配。
精確字段搜索
在字段中查找單個字詞是很好的,但有時你想要匹配字詞或短語的確切序列。例如,我們可以執行一個查詢,該查詢將僅匹配包含“rock”和“climbing”的員工記錄,並在短語“rock climbing”中顯示彼此相鄰的單詞。
為此,我們使用改為match_phrase查詢:
GET /megacorp/employee/_search
{
"query" : {
"match_phrase" : {
"about" : "rock climbing"
}
}
}
僅返回John Smith的文檔

高亮搜索結果
許多應用程序喜歡從每個搜索結果突出顯示文本片段,以便用戶可以看到文檔與查詢匹配的原因。在Elasticsearch中檢索突出顯示的片段很容易。
讓我們重新運行我們以前的查詢,但添加一個新的highlight參數:
GET /megacorp/employee/_search
{
"query" : {
"match_phrase" : {
"about" : "rock climbing"
}
},
"highlight": {
"fields" : {
"about" : {}
}
}
}
當我們運行此查詢時,將返回與之前相同的返回,但現在我們在響應中得到一個新的部分,稱為突出顯示。
這包含來自about字段的文字片段,其中包含在 HTML標記中包含的匹配單詞:

分析
最后,我們來到我們的最后一個業務需求:允許管理員在員工目錄上運行分析。Elasticsearch具有稱為聚合的功能,允許您對數據生成復雜的分析。它類似於GROUP BY中的SQL,但功能更強大。
例如,讓我們找到我們的員工最喜歡的興趣:
GET /megacorp/employee/_search
{
"aggs": {
"all_interests": {
"terms": { "field": "interests" }
}
}
}
如果Elasticsearch 5版本以前,將會返回:
{
...
"hits": { ... },
"aggregations": {
"all_interests": {
"buckets": [
{
"key": "music",
"doc_count": 2
},
{
"key": "forestry",
"doc_count": 1
},
{
"key": "sports",
"doc_count": 1
}
]
}
}
}
我們可以看到,兩個員工對音樂感興趣,一個在林業,一個在體育。這些聚合不是預先計算的,它們是從與當前查詢匹配的文檔即時生成的。
然而如果我們使用的是Elasticsearch 5版本以上的話,將會出現如下異常:

我們可以查看Elasticsearch 5.0文檔——Fielddata is disabled on text fields by default
大概的意思是:Fielddata可以消耗大量的堆空間,特別是在加載高基數文本字段時。一旦fielddata已經加載到堆中,它在該段的生存期內保持。此外,加載fielddata是一個昂貴的過程,可以導致用戶體驗延遲命中。
所以fielddata默認禁用。如果嘗試對文本字段上的腳本進行排序,聚合或訪問值,就會看到這個異常,具體使用可以參考手冊。
總結
這個小例子是一個很好的演示了什么是Elasticsearch。它只是很膚淺的介紹了簡單的使用,許多功能被省略,以保持簡短。但是這也突出了開始構建高級搜索功能是多么容易。
轉載請注明出處。
作者:wuxiwei
出處:http://www.cnblogs.com/wxw16/p/6185378.html
