1. 程式人生 > >ElasticSearch教程(二)—— 基本使用

ElasticSearch教程(二)—— 基本使用

基本使用

基本概念

ElasticSearch是面向文件的,它儲存文件,並索引每個文件的內容使之可以被索引。ES選擇json作為文件序列化格式。

索引:名詞,類似一個數據庫,是一個儲存關係性文件的地方。

索引:動詞,把關係型文件存到索引的過程,是插入。

ES使用倒排索引來索引文件,只有在倒排索引中存在的屬性才能被搜尋。

倒排索引

倒排索引,文件經過分詞器分出許多詞根,並把詞根和文件的關聯關係存在一個文件中。

term doc1 doc2
run X
jump X
swim X X
fight X

當搜尋一個語句,回返回所有存在該term的文件。如搜尋run swim,doc1,doc2都存在索引,但doc1的匹配度更高。

term doc1 doc2
run X
swim X X
total 2 1

倒排索引存在的問題是必須完全按照倒排索引的欄位來查詢,只要單詞不一樣,就搜尋不到匹配文件。如倒排索引分出的詞是swiming,搜尋swim,SWIM都不會匹配到。

可以的做法,規範搜尋詞,如SWIM後臺轉成swim去匹配。對於swiming,users這類的詞,可以通過詞幹抽取,把swiming抽成swim,users抽成user。倒排索引資料會很大,需要壓縮。

索引文件

一個elasticSearch叢集有多個索引(index),每個索引有多個type(型別),每個type有多個屬性。

對於索引僱員目錄,我們這麼做

  • 每個僱員都是一個文件
  • 每個文件我們都放到employ型別下
  • employ型別在索引megacorp中
  • 該索引儲存在elaticSearch叢集內。
curl -X PUT "localhost:9200/megacorp/employee/1" -H 'Content-type: application/json;' -d'
{
    "first_name": "John";
    "last_name": "Smith"
; "age": 25; "about": "I love to go rock climbing"; "interests": ["sports", "music"] } '

返回

{
    "_index": "megacorp",
    "_type": "employee",
    "_id": "1",
    "_version": 1,
    "result": "created",
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 0,
    "_primary_term": 1
}
屬性 含義
_index 存放索引
_type 存放型別
_shards 存放分片資訊
_id 插入的id
total 總分片
successful 成功操作分片
failed 失敗操作分片
result 操作型別,create,update等

多插入幾條資料

curl -X PUT "localhost:9200/megacorp/employee/2" -H 'Content-type: application/json;' -d'
{
    "first_name" :  "Jane",
    "last_name" :   "Smith",
    "age" :         32,
    "about" :       "I like to collect rock albums",
    "interests":  [ "music" ]
}
'

curl -X PUT "localhost:9200/megacorp/employee/3" -H 'Content-type: application/json;' -d'
{
    "first_name" :  "Douglas",
    "last_name" :   "Fir",
    "age" :         35,
    "about":        "I like to build cabinets",
    "interests":  [ "forestry" ]
}
'

檢索文件

通過GET來檢索文件。

curl -X GET "localhost:9200megacrp/employee/1"

返回結果

{
    "_index": "megacorp",
    "_type": "employee",
    "_id": "2",
    "_version": 1,
    "found": true,
    "_source": {
        "first_name": "Marx",
        "last_name": "Smith",
        "age": 25,
        "about": "I love to go rock climbing",
        "interests": ["sports", "music"]
    }
}

使用GET檢索文件,使用PUT索引文件(insert/update)通過_index,使用DELETE命令來刪除文件,使用HEAD指令來檢查文件是否存在。

ES支援通過一個string作為引數查詢,也可以使用request body查詢

使用string檢索

上面的例子是通過index直接訪問改文件,下面的是通過查詢得到文件結果。

通過_search可以搜尋索引庫中,某個type下的文件。展示所有文件。

curl -X GET "localhost:9200/megacorp/employee/_search"

查詢first_name未Marx的所有文件

curl -X GET "localhost:9200/megacorp/employee/_search?q=first_name:Marx"

簡單檢索是一個即席查詢。

即席查詢是使用者根據自己的需求,靈活的選擇查詢條件,系統能夠根據使用者的選擇生成相應的統計報表。即席查詢與普通應用查詢最大的不同是普通的應用查詢是定製開發的,而即席查詢是由使用者自定義查詢條件的。如”select id from user where user_no = “+”001”。

另一種查詢是引數化查詢,如”select id from user where user_no = #{userNo}”。

對於多個條件的查詢,使用+將多個條件連線起來。但在url中,+被轉為空格,所以必須用它UTF編碼%2B

curl -X GET "localhost:9200/megacorp/employee/_search?q=first_name:Marx%2B_index:2"

也可以不指定index而進行全叢集查詢

curl -X GET "localhost:9200/_all/_search?q=first_name:Marx"

由於即席查詢允許使用者在索引的任何欄位上執行可能較慢且重量級查詢,這可能會暴露隱私資訊,甚至將叢集拖垮。所以不建議想使用者暴露查詢查詢字串搜尋功能。

使用request body檢索

使用request body可以完成一些複雜的查詢,如查詢first_name為John的資料。

curl -X GET "localhost:9200/merp/employee/_search" -H 'Content-type: application/json' -d'
{
    "query": {
        "match": {
            "first_name": "John"
        }
    }
}

結果

{
    "took": 2,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 1,
        "max_score": 0.2876821,
        "hits": [{
            "_index": "megacorp",
            "_type": "employee",
            "_id": "1",
            "_score": 0.2876821,
            "_source": {
                "first_name": "John",
                "last_name": "Smith",
                "age": 25,
                "about": "I love to go rock climbing",
                "interests": ["sports", "music"]
            }
        }]
    }
}

可以加上過濾年齡過濾

curl -X GET "localhost:9200/merp/employee/_search" -H 'Content-type: application/json' -d'
{
    "query": {
        "bool": {
            "must": {
                "match": {
                    "first_name": "John"
                }
            },
            "filter": {
                "range": {
                    "age": {
                        "gt": 30
                    }
                }
            }
        }
    }
}'

ES的搜尋是可以看到文件匹配分數的,這是mysql不具備的。如搜尋”go climbing”,它會搜尋文件屬性中存在”go”,”climbing”的文件,並給予匹配度。

curl -X GET "localhost:9200/megacorp/employee/_search" -H 'Content-type: application/json' -d'
{"query":{"match":{"about":"go climbing"}}}'
短語搜尋

按整個引數去檢索,而不是把它分詞檢索,如檢索”rock climbing”短語,使用match_phrase

curl -X GET "localhost:9200/megacorp/employee/_search" -H 'Content-type: application/json' -d'
{
    "query": {
        "match_phrase": {
            "about": "rock climbing"
        }
    }
}'
高亮顯示

加上”highlight”,可以將屬性中所有匹配的關鍵字加上<em></em>高亮顯示。屬性名支援萬用字元表示法。

curl -X GET "localhost:9200/megacorp/employee/_search" -H 'Content-type: application/json' -d'           
{
    "query": {
        "match_phrase": {
            "about": "rock climbing"
        }
    },
    "highlight": {
        "fields": {
            "about": {}
        }
    }
}'

結果

{"took":3,"timed_out":false,"_shards":{"total":5,"successful":5,"skipped":0,"failed":0},"hits":{"total":1,"max_score":0.5753642,"hits":[{"_index":"megacorp","_type":"employee","_id":"1","_score":0.5753642,"_source":
{
    "first_name" : "John",
    "last_name" :  "Smith",
    "age" :        25,
    "about" :      "I love to go rock climbing",
    "interests": [ "sports", "music" ]
}
,"highlight":{"about":["I love to go <em>rock</em> <em>climbing</em>"]}}]}}
聚合檢索
curl -X GET "localhost:9200/megacorp/employee/_search" -H 'Content-type: application/json' -d'
{"aggs": {"all_interests": {"terms": {"field": "interests" } } } }'

注意,使用聚合檢索的屬性不能是text,es6對於String分成了支援聚合的keyword和不支援聚合的text。否則會提示

Fielddata is disabled on text fields by default. Set fielddata=true on [interests] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory. Alternatively use a keyword field instead.