ElasticSearch 5學習(5)——第一個例子(很實用)


想要知道ElasticSearch是如何使用的,最快的方式就是通過一個簡單的例子,第一個例子將會包括基本概念如索引、搜索、和聚合等,需求是關於公司管理員工的一些業務。

員工文檔索引

業務首先需要存儲員工數據。這將采取一個員工文檔的形式:單個文檔表示單個員工。在Elasticsearch中存儲數據的行為稱為索引,但是在索引文檔之前,我們需要決定在哪里存儲它。

在Elasticsearch中,文檔屬於某個類型,這些類型位於索引中。可以繪制一些(粗略)與傳統關系數據庫的對比:

Relational DB  ⇒ Databases ⇒ Tables ⇒ Rows      ⇒ Columns
Elasticsearch  ⇒ Indices   ⇒ Types  ⇒ Documents ⇒ Fields

Elasticsearch集群可以包含多個索引(數據庫),這些索引又包含多個類型(表)。這些類型包含多個文檔(行),每個文檔都有多個字段(列)。

您可能已經注意到,在Elasticsearch的上下文中,索引被重載了幾個含義。如下:

  1. 索引(名詞):正如前面所解釋的那樣,索引就像傳統的關系數據庫中的數據庫一樣。它是存儲相關文檔的地方。index的復數形式是indices或indexes。
  2. 索引(動詞):索引一個文檔是將一個文檔存儲在索引(名詞)中,以便它可以檢索和查詢。它很像插入關鍵詞SQL。此外,如果文檔已經存在,新的文檔將取代舊的。
  3. 倒排索引:關系數據庫中增加一個索引,如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文本,包含所有關於該員工的信息。

注意:

  1. 如果執行過程中失敗了,可能存在的原因是elasticsearch默認配置中不允許自動創建索引,所以我們可以先簡單在elasticsearch.yml配置文件添加action.auto_create_index:true,允許自動創建索引。
  2. 沒有必要首先執行任何管理任務,如創建一個索引或指定每個字段所包含的數據類型。我們可以直接索引一個文檔。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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM