ElasticSearch(1)-入門


下一篇 Elastic Search基礎(2)

相關文檔:

 

Gitbook[中文未完整]: http://learnes.net/

 

Gitbook[英文完整]:https://allen8807.gitbooks.io/elasticsearch-definitive-guide-en/content/

 

權威指南: http://es.xiaoleilu.com/

 

官網: https://www.elastic.co/guide/index.html

 

官網API:https://www.elastic.co/guide/en/elasticsearch/reference/1.7/index.html

 

一、ES介紹

1、什么是es?

Elasticsearch 是一個建立在全文搜索引擎 Apache Lucene(TM) 基礎上的搜索引擎,可以說 Lucene 是當今最先進,最高效的全功能開源搜索引擎框架。但是 Lucene 只是一個框架,要充分利用它的功能,你需要使用 JAVA,並且在你的程序中集成 Lucene。更糟的是,你需要做很多的學習了解,才能明白它是如何運行的,Lucene 確實非常復雜。

當然 Elasticsearch 並不僅僅是 Lucene 那么簡單,它不僅包括了全文搜索功能,還可以進行以下工作:

  • 分布式實時存儲,並將每一個字段都編入索引,使其可以被搜索(准實時,有輕微延遲,1s左右)。
  • 實時分析的分布式搜索引擎。
  • 可以擴展到上百台服務器,處理PB級別的結構化或非結構化數據。

2、es特性:

  • 支持Restful,大量的Restful api
  • json風格
  • 分布式索引和搜索
  • 天然支持shard,replication
  • 高性能,易擴展,使用簡單

3、ES不僅僅是搜索?

  • es是否可以作為一個NOSQL,看上去並不可以,但是這是一個合理的場景。就像MongoDB在MapReduce的基礎上使用分片技術同樣可以完成部分Hadoop可以做的工作,也就是說一切都和具體場景有關。
  • es已經超越了最初的設定角色:一個純搜索引擎。但這依舊是它的核心,如果你有數百萬的文檔需要通過關鍵詞進行定位時,Elasticsearch就是最好的選擇。如果你僅僅把它當做一個JSON文檔,那它就是一個NOSQL數據庫,同時支持輕度的數據分析功能。
  • 而且,es可以很輕松和hadoop集群。

二、ES中的基礎概念

https://www.elastic.co/guide/en/elasticsearch/reference/current/_basic_concepts.html

2.1 Document:文檔

  • 內容為json格式,它指的是在Elasticsearch中被存儲到唯一ID下的由最高級或者根對象 (root object )序列化而來的JSON.
  • 由_index+_type+_id共同決定一個唯一的文檔
  • _type是一個邏輯概念,並不是物理概念

下面是對三者的詳細解釋:

(1) _index

  類似於傳統數據庫中的"庫"-存儲並且索引數據的地方

  在ES中,我們的數據都在分片中被存儲以及索引,索引是一個邏輯命名空間,它可以將一個或者多個分片組合在一起。

(2) _type

  在ES中我們使用同樣_type的文檔來代表同類,因為它們的數據結構是相同的

  每一個類型都有自己的mapping或者結構定義,它們定義了當前類型的數據結構,類似於數據表中的列。

    Documents of all types can be stored in the same index, but the mapping for type tell ES how the data in each document should be indexed.

(3) _id

  id是一個字符串,當它與_index以及_type組合時,就可以來代表Elasticsearch中一個特定的文檔。我們創建了一個新的文檔時,你可以自己提供一個_id,或者也可以讓Elasticsearch幫你生成一個

2.2 Index:索引

文檔通過索引API被索引——存儲並使其可搜索。但是最開始我們需要決定我們將文檔存儲在哪里。正如之前提到的,一篇文檔通過_index_type以及_id來確定它的唯一性

如果我們的索引叫做"website",我們的類型叫做 "blog",然后我們選擇"123"作為ID的編號。這時,請求就是這樣的:

 

PUT /website/blog/123
{
  "title": "My first blog entry",
  "text":  "Just trying this out...",
  "date":  "2014/01/01"
}

2.3 分片、高可用、集群、節點

  • ES采用的是服務端分片技術,對客戶端透明且容易擴展。
  • 多個node(es實例)通過cluster(集群名字)自動加入一個集群,每個cluseter有一個master node。
  • master node管理集群的變更,例如新建或者刪除索引,增加或者移除節點等。master node不會參與文檔級別的變更或者搜索,這意味着在流量增長的時候,該主節點不會成為集群的瓶頸。
  • 分片(shard) 是 工作單元(worker unit) 底層的一員,它只負責保存索引中所有數據的一小片。在 elasticsearch 中,分片用來分配集群中的數據。把分片想象成一個數據的容器。
  • 數據被存儲在分片中,然后分片又被分配在集群的節點上。
  • 當你的集群擴展或者縮小時,elasticsearch 會自動的在節點之間遷移分配分片,以便集群保持均衡。
  • es通過在分片級別實現主從機制來保證高可用,同時服務於搜索和檢索這種只讀請求。
    •   主分片primary shard就是數據的切片,由於是數據存儲而不是緩存,primary shard的數目才創建索引時指定且不可更改
    •   從分片就是數據的副本,可以隨時更改數目。

下面是使用head插件截圖,有一個索引bank,下面有0,1,2,3,4共5個主分片,每個分片有1個從分片。

2.4 映射概念:

  映射類似於數據庫中的表結構,每一個索引都有一個映射,它定義了每一個字段類型,以及一個索引范圍內的設置。一個映射可以被事先定義,如果沒有事先定義,也存儲文檔的時候ES也會嘗試進行自動識別。

  mapping機制也被ES用於字段分析,每個字段都有一種確定的類型

  field(字段)則非常好理解,類似於MySQL中列的概念,每個field都有一個類型,這個關系被定義在mapping中。重要的是,ES中,每一個字段都會被索引,因此其查詢能力非常的強。

  source field:默認情況下,document的原始內容被存儲在_source中,查詢的時候返回的是一個精確的json字符串。

三、安裝

依賴於jdk,依賴於java的都好安裝,直接解壓或者rpm包都可以,略

集群搭建也很簡單,一般的方式,同步時間,無ssh密鑰通信等.

其配置文件解釋的非常詳細...

systemctl daemon-reload

systemctl start elasticsearch.service

如果出錯JAVA_HOME找不到,可以在/etc/sysconfig/elasticsearch中指定環境變量JAVA_HOME

最近發現2.3版本的集群配置,不僅僅是配置為同一個cluster name,還需要大致修改一下..

# 修改集群名稱
cluster.name: cluster_name
# 修改節點名稱
node.name: node-01
# 修改綁定IP地址
network.host 0.0.0.0
# 自定義端口
http.port: 9200
# 自動探測同集群節點的Hosts列表
discovery.zen.ping.unicast.hosts: ["192.168.131.129"]
# 組成集群的最少節點數
discovery.zen.minimum_master_nodes: 2

 

安裝插件:

插件集地址: http://www.kailing.pub/article/index/arcid/87.html

  插件擴展的功能:

    添加自定義的映射類型、自定義分詞器、本地腳本、自定義節點發現方式

  安裝:

    直接將plugin放置於插件目錄

    使用命令plugin

先安裝一些常用的插件:

1. 安裝Head,免費

  ./plugin install mobz/elasticsearch-head

2. 安裝marvel,收費的,但是官方推薦...

3. 安裝分詞器ik

  https://github.com/medcl/elasticsearch-analysis-ik上有源碼,因此可以使用源碼安裝

  修改默認配置為:index.analysis.analyzer.default.type: ik

 

四、客戶端

1、java客戶端:

Elasticsearch為Java用戶提供了兩種內置客戶端:

節點客戶端(node client):

節點客戶端以無數據節點(none data node)身份加入集群,換言之,它自己不存儲任何數據,但是它知道數據在集群中的具體位置,並且能夠直接轉發請求到對應的節點上。

傳輸客戶端(Transport client):

這個更輕量的傳輸客戶端能夠發送請求到遠程集群。它自己不加入集群,只是簡單轉發請求給集群中的節點。

說明:兩個Java客戶端都通過9300端口與集群交互,使用Elasticsearch傳輸協議(Elasticsearch Transport Protocol)。集群中的節點之間也通過9300端口進行通信。如果此端口未開放,你的節點將不能組成集群。

 Tips: Java客戶端所在的Elasticsearch版本必須與集群中其他節點一致,否則,它們可能互相無法識別。

2、基於HTTP協議,以JSON為數據交互格式的RESTful API

其他所有程序語言都可以使用RESTful API,通過9200端口的與Elasticsearch進行通信,你可以使用你喜歡的WEB客戶端,事實上,如你所見,你甚至可以通過curl命令與Elasticsearch通信。

NOTE

Elasticsearch官方提供了多種程序語言的客戶端——Groovy,Javascript, .NET,PHP,Perl,Python,以及 Ruby——還有很多由社區提供的客戶端和插件,所有這些可以在文檔中找到

向Elasticsearch發出的請求的組成部分與其它普通的HTTP請求是一樣的,下面是curl命令說明:

curl -X<VERB> '<PROTOCOL>://<HOST>:<PORT>/<PATH>?<QUERY_STRING>' -d '<BODY>'
  • VERB HTTP方法:GETPOSTPUTHEADDELETE
  • PROTOCOL http或者https協議(只有在Elasticsearch前面有https代理的時候可用)
  • HOST Elasticsearch集群中的任何一個節點的主機名,如果是在本地的節點,那么就叫localhost
  • PORT Elasticsearch HTTP服務所在的端口,默認為9200
  • PATH API路徑(例如_count將返回集群中文檔的數量),PATH可以包含多個組件,例如_cluster/stats或者_nodes/stats/jvm
  • QUERY_STRING 一些可選的查詢請求參數,例如?pretty參數將使請求返回更加美觀易讀的JSON數據
  • BODY 一個JSON格式的請求主體(如果請求需要的話)

五、索引

下面我們以一個實例來演示相關概念

假設我們剛好在Megacorp工作,這時人力資源部門出於某種目的需要讓我們創建一個員工目錄,這個目錄用於促進人文關懷和用於實時協同工作,所以它有以下不同的需求:

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

索引員工文檔

我們首先要做的是存儲員工數據,每個文檔代表一個員工。在Elasticsearch中存儲數據的行為就叫做索引(indexing),不過在索引之前,我們需要明確數據應該存儲在哪里。

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

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

索引不同於數據庫的概念

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

curl -XPUT 'http://localhost:9200/megacorp/employee/1' -d '
{
"first_name" : "John",
"last_name" : "Smith",
"age" : 25,
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
}
'

可以使用head插件查看:

下面使用類似的操作加入更多的信息:

curl -XPUT 'http://localhost:9200/megacorp/employee/2' -d '
{
    "first_name" :  "Jane",
    "last_name" :   "Smith",
    "age" :         32,
    "about" :       "I like to collect rock albums",
    "interests":  [ "music" ]
}
'

curl -XPUT 'http://localhost:9200/megacorp/employee/3' -d '
{
    "first_name" :  "Douglas",
    "last_name" :   "Fir",
    "age" :         35,
    "about":        "I like to build cabinets",
    "interests":  [ "forestry" ]
}
'

六、檢索文檔

直接使用GET請求,非常簡單

[root@ysz211 ~]# curl 'http://localhost:9200/megacorp/employee/1?pretty'
{
  "_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" ]
  }
}

Tips: RESTFUL風格的API

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

6.1 簡單搜索

GET請求非常簡單——你能輕松獲取你想要的文檔。讓我們來進一步嘗試一些東西,比如簡單的搜索!

我們嘗試一個最簡單的搜索全部員工的請求:

curl 'http://localhost:9200/megacorp/employee/_search?pretty'

返回結果大致如下:

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

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

curl 'http://localhost:9200/megacorp/employee/_search?q=last_name:Smith&pretty'

6.2 使用DSL語句查詢

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

DSL(Domain Specific Language特定領域語言)以JSON請求體的形式出現。我們可以這樣表示之前關於“Smith”的查詢:

 

curl 'http://localhost:9200/megacorp/employee/_search?pretty' -d '
{
    "query" : {
        "match" : {
            "last_name" : "Smith"
        }
    }
}
'

這會返回與之前查詢相同的結果。

更復雜的搜索

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

 

curl 'http://localhost:9200/megacorp/employee/_search?pretty' -d '
{
    "query" : {
        "filtered" : {
            "filter" : {
                "range" : {
                    "age" : { "gt" : 30 }
                }
            },
            "query" : {
                "match" : {
                    "last_name" : "smith"
                }
            }
        }
    }
}
'

注意上面的例子同時使用了過濾器和match進行搜索。

全文搜索

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

我們將會搜索所有喜歡“rock climbing”的員工:

curl 'http://localhost:9200/megacorp/employee/_search?pretty' -d '
{
    "query" : {
        "match" : {
            "about" : "rock climbing"
        }
    }
}
'

這里返回的結果可能會讓人疑惑,首先我們來看一下結果:

{
  "took" : 10,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : 0.18985549,
    "hits" : [ {
      "_index" : "megacorp",
      "_type" : "employee",
      "_id" : "1",
      "_score" : 0.18985549,
      "_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" : 0.019691018,
      "_source" : {
        "first_name" : "Jane",
        "last_name" : "Smith",
        "age" : 32,
        "about" : "I like to collect rock albums",
        "interests" : [ "music" ]
      }
    } ]
  }
}

這里居然出現了2個結果,其中第二個只包含了rock,這就是結果相關性評分

默認情況下,Elasticsearch根據結果相關性評分來對結果集進行排序,所謂的「結果相關性評分」就是文檔與查詢條件的匹配程度。很顯然,排名第一的John Smithabout字段明確的寫到“rock climbing”

但是為什么Jane Smith也會出現在結果里呢?原因是“rock”在她的abuot字段中被提及了。因為只有“rock”被提及而“climbing”沒有,所以她的_score要低於John。

 

這個例子很好的解釋了Elasticsearch如何在各種文本字段中進行全文搜索,並且返回相關性最大的結果集。相關性(relevance)的概念在Elasticsearch中非常重要,而這個概念在傳統關系型數據庫中是不可想象的,因為傳統數據庫對記錄的查詢只有匹配或者不匹配。

 

短語搜索

目前我們可以在字段中搜索單獨的一個詞,這挺好的,但是有時候你想要確切的匹配若干個單詞或者短語(phrases)。例如我們想要查詢同時包含"rock"和"climbing"(並且是相鄰的)的員工記錄。

要做到這個,我們只要將match查詢變更為match_phrase查詢即可:

curl 'http://localhost:9200/megacorp/employee/_search?pretty' -d '
{
    "query" : {
        "match_phrase" : {
            "about" : "rock climbing"
        }
    }
}
'

高亮我們的搜索

很多應用喜歡從每個搜索結果中高亮(highlight)匹配到的關鍵字,這樣用戶可以知道為什么這些文檔和查詢相匹配。在Elasticsearch中高亮片段是非常容易的。

讓我們在之前的語句上增加highlight參數:

curl 'http://localhost:9200/megacorp/employee/_search?pretty' -d '
{
    "query" : {
        "match_phrase" : {
            "about" : "rock climbing"
        }
    },
    "highlight": {
        "fields" : {
            "about" : {}
        }
    }
}
'

當我們運行這個語句時,會命中與之前相同的結果,但是在返回結果中會有一個新的部分叫做highlight,這里包含了來自about字段中的文本,並且用<em></em>來標識匹配到的單詞。

七、聚合

分析

最后,我們還有一個需求需要完成:允許管理者在職員目錄中進行一些分析。 Elasticsearch有一個功能叫做聚合(aggregations),它允許你在數據上生成復雜的分析統計。它很像SQL中的GROUP BY但是功能更強大。

舉個例子,讓我們找到所有職員中最大的共同點(興趣愛好)是什么:

curl 'http://localhost:9200/megacorp/employee/_search?pretty' -d '
{
  "aggs": {
    "all_interests": {
      "terms": { "field": "interests" }
    }
  }
}
'

暫時先忽略語法只看查詢結果:

{
   ...
   "hits": { ... },
   "aggregations": {
      "all_interests": {
         "buckets": [
            {
               "key":       "music",
               "doc_count": 2
            },
            {
               "key":       "forestry",
               "doc_count": 1
            },
            {
               "key":       "sports",
               "doc_count": 1
            }
         ]
      }
   }
}

我們可以看到兩個職員對音樂有興趣,一個喜歡林學,一個喜歡運動。這些數據並沒有被預先計算好,它們是實時的從匹配查詢語句的文檔中動態計算生成的。如果我們想知道所有姓"Smith"的人最大的共同點(興趣愛好),我們只需要增加合適的語句既可:

curl 'http://localhost:9200/megacorp/employee/_search?pretty' -d '
{
  "query": {
    "match": {
      "last_name": "smith"
    }
  },
  "aggs": {
    "all_interests": {
      "terms": {
        "field": "interests"
      }
    }
  }
}
'

聚合也允許分級匯總。例如,讓我們統計每種興趣下職員的平均年齡:

curl 'http://localhost:9200/megacorp/employee/_search?pretty' -d '
{
    "aggs" : {
        "all_interests" : {
            "terms" : { "field" : "interests" },
            "aggs" : {
                "avg_age" : {
                    "avg" : { "field" : "age" }
                }
            }
        }
    }
}
'

雖然這次返回的聚合結果有些復雜,但任然很容易理解:

  ...
  "all_interests": {
     "buckets": [
        {
           "key": "music",
           "doc_count": 2,
           "avg_age": {
              "value": 28.5
           }
        },
        {
           "key": "forestry",
           "doc_count": 1,
           "avg_age": {
              "value": 35
           }
        },
        {
           "key": "sports",
           "doc_count": 1,
           "avg_age": {
              "value": 25
           }
        }
     ]
  }

 


免責聲明!

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



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