全文搜索引擎 ElasticSearch 入門教程
全文搜索屬於最常見的需求,開源的 ElasticSearch (以下簡稱 Elastic)是目前全文搜索引擎的首選。
它可以快速地儲存、搜索和分析海量數據。維基百科、Stack Overflow、Github 都採用它。
Elastic 的底層是開源庫 Lucene。但是,你沒法直接用 Lucene,必須自己寫代碼去調用它的介面。Elastic 是 Lucene 的封裝,提供了 REST API 的操作介面,開箱即用。
本文從零開始,講解如何使用 Elastic 搭建自己的全文搜索引擎。每一步都有詳細的說明,大家跟著做就能學會。
一、安裝
Elastic 需要 Java 8 環境。如果你的機器還沒安裝 Java,可以參考這篇文章,注意要保證環境變數JAVA_HOME正確設置。
安裝完 Java,就可以跟著官方文檔安裝 Elastic。直接下載壓縮包比較簡單。
$ wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.5.1.zip
$ unzip elasticsearch-5.5.1.zip
$ cd elasticsearch-5.5.1/
接著,進入解壓後的目錄,運行下面的命令,啟動 Elastic。
$ ./bin/elasticsearch
如果這時報錯"max virtual memory areas vm.maxmapcount [65530] is too low",要運行下面的命令。
$ sudo sysctl -w vm.max_map_count=262144
如果一切正常,Elastic 就會在默認的9200埠運行。這時,打開另一個命令行窗口,請求該埠,會得到說明信息。
$ curl localhost:9200
{
"name" : "atntrTf",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "tf9250XhQ6ee4h7YI11anA",
"version" : {
"number" : "5.5.1",
"build_hash" : "19c13d0",
"build_date" : "2017-07-18T20:44:24.823Z",
"build_snapshot" : false,
"lucene_version" : "6.6.0"
},
"tagline" : "You Know, for Search"
}
上面代碼中,請求9200埠,Elastic 返回一個 JSON 對象,包含當前節點、集群、版本等信息。
按下 Ctrl + C,Elastic 就會停止運行。
默認情況下,Elastic 只允許本機訪問,如果需要遠程訪問,可以修改 Elastic 安裝目錄的config/elasticsearch.yml文件,去掉network.host的注釋,將它的值改成0.0.0.0,然後重新啟動 Elastic。
network.host: 0.0.0.0
上面代碼中,設成0.0.0.0讓任何人都可以訪問。線上服務不要這樣設置,要設成具體的 IP。
二、基本概念
2.1 Node 與 Cluster
Elastic 本質上是一個分散式資料庫,允許多台伺服器協同工作,每台伺服器可以運行多個 Elastic 實例。
單個 Elastic 實例稱為一個節點(node)。一組節點構成一個集群(cluster)。
2.2 Index
Elastic 會索引所有欄位,經過處理後寫入一個反向索引(Inverted Index)。查找數據的時候,直接查找該索引。
所以,Elastic 數據管理的頂層單位就叫做 Index(索引)。它是單個資料庫的同義詞。每個 Index (即資料庫)的名字必須是小寫。
下面的命令可以查看當前節點的所有 Index。
$ curl -X GET "http://localhost:9200/_cat/indices?v"
2.3 Document
Index 裡面單條的記錄稱為 Document(文檔)。許多條 Document 構成了一個 Index。
Document 使用 JSON 格式表示,下面是一個例子。
{
"user": "張三",
"title": "工程師",
"desc": "資料庫管理"
}
同一個 Index 裡面的 Document,不要求有相同的結構(scheme),但是最好保持相同,這樣有利於提高搜索效率。
2.4 Type
Document 可以分組,比如weather這個 Index 裡面,可以按城市分組(北京和上海),也可以按氣候分組(晴天和雨天)。這種分組就叫做 Type,它是虛擬的邏輯分組,用來過濾 Document。
不同的 Type 應該有相似的結構(schema),舉例來說,id欄位不能在這個組是字元串,在另一個組是數值。這是與關係型資料庫的表的一個區別。性質完全不同的數據(比如products和logs)應該存成兩個 Index,而不是一個 Index 裡面的兩個 Type(雖然可以做到)。
下面的命令可以列出每個 Index 所包含的 Type。
$ curl "localhost:9200/_mapping?pretty=true"
根據規劃,Elastic 6.x 版只允許每個 Index 包含一個 Type,7.x 版將會徹底移除 Type。
三、新建和刪除 Index
新建 Index,可以直接向 Elastic 伺服器發出 PUT 請求。下面的例子是新建一個名叫weather的 Index。
$ curl -X PUT "localhost:9200/weather"
伺服器返回一個 JSON 對象,裡面的acknowledged欄位表示操作成功。
{
"acknowledged":true,
"shards_acknowledged":true
}
然後,我們發出 DELETE 請求,刪除這個 Index。
$ curl -X DELETE "localhost:9200/weather"
四、中文分詞設置
首先,安裝中文分詞插件。這裡使用的是 ik,也可以考慮其他插件(比如 smartcn)。
$ ./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v5.5.1/
elasticsearch-analysis-ik-5.5.1.zip
上面代碼安裝的是5.5.1版的插件,與 Elastic 5.5.1 配合使用。
接著,重新啟動 Elastic,就會自動載入這個新安裝的插件。
然後,新建一個 Index,指定需要分詞的欄位。這一步根據數據結構而異,下面的命令只針對本文。基本上,凡是需要搜索的中文欄位,都要單獨設置一下。
$ curl -X PUT "localhost:9200/accounts" -d "
{
"mappings": {
"person": {
"properties": {
"user": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_max_word"
},
"title": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_max_word"
},
"desc": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_max_word"
}
}
}
}
}"
上面代碼中,首先新建一個名稱為accounts的 Index,裡面有一個名稱為person的 Type。person有三個欄位。
user
title
desc
這三個欄位都是中文,而且類型都是文本(text),所以需要指定中文分詞器,不能使用默認的英文分詞器。
Elastic 的分詞器稱為 analyzer。我們對每個欄位指定分詞器。
"user": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_max_word"
}
上面代碼中,analyzer是欄位文本的分詞器,search_analyzer是搜索詞的分詞器。ik_max_word分詞器是插件ik提供的,可以對文本進行最大數量的分詞。
五、數據操作
5.1 新增記錄
向指定的 /Index/Type 發送 PUT 請求,就可以在 Index 裡面新增一條記錄。比如,向/accounts/person發送請求,就可以新增一條人員記錄。
$ curl -X PUT "localhost:9200/accounts/person/1" -d "
{
"user": "張三",
"title": "工程師",
"desc": "資料庫管理"
}"
伺服器返回的 JSON 對象,會給出 Index、Type、Id、Version 等信息。
{
"_index":"accounts",
"_type":"person",
"_id":"1",
"_version":1,
"result":"created",
"_shards":{"total":2,"successful":1,"failed":0},
"created":true
}
如果你仔細看,會發現請求路徑是/accounts/person/1,最後的1是該條記錄的 Id。它不一定是數字,任意字元串(比如abc)都可以。
新增記錄的時候,也可以不指定 Id,這時要改成 POST 請求。
$ curl -X POST "localhost:9200/accounts/person" -d "
{
"user": "李四",
"title": "工程師",
"desc": "系統管理"
}"
上面代碼中,向/accounts/person發出一個 POST 請求,添加一個記錄。這時,伺服器返回的 JSON 對象裡面,_id欄位就是一個隨機字元串。
{
"_index":"accounts",
"_type":"person",
"_id":"AV3qGfrC6jMbsbXb6k1p",
"_version":1,
"result":"created",
"_shards":{"total":2,"successful":1,"failed":0},
"created":true
}
注意,如果沒有先創建 Index(這個例子是accounts),直接執行上面的命令,Elastic 也不會報錯,而是直接生成指定的 Index。所以,打字的時候要小心,不要寫錯 Index 的名稱。
5.2 查看記錄
向/Index/Type/Id發出 GET 請求,就可以查看這條記錄。
$ curl "localhost:9200/accounts/person/1?pretty=true"
上面代碼請求查看/accounts/person/1這條記錄,URL 的參數pretty=true表示以易讀的格式返回。
返回的數據中,found欄位表示查詢成功,_source欄位返回原始記錄。
{
"_index" : "accounts",
"_type" : "person",
"_id" : "1",
"_version" : 1,
"found" : true,
"_source" : {
"user" : "張三",
"title" : "工程師",
"desc" : "資料庫管理"
}
}
如果 Id 不正確,就查不到數據,found欄位就是false。
$ curl "localhost:9200/weather/beijing/abc?pretty=true"
{
"_index" : "accounts",
"_type" : "person",
"_id" : "abc",
"found" : false
}
5.3 刪除記錄
刪除記錄就是發出 DELETE 請求。
$ curl -X DELETE "localhost:9200/accounts/person/1"
這裡先不要刪除這條記錄,後面還要用到。
5.4 更新記錄
更新記錄就是使用 PUT 請求,重新發送一次數據。
$ curl -X PUT "localhost:9200/accounts/person/1" -d "
{
"user" : "張三",
"title" : "工程師",
"desc" : "資料庫管理,軟體開發"
}"
{
"_index":"accounts",
"_type":"person",
"_id":"1",
"_version":2,
"result":"updated",
"_shards":{"total":2,"successful":1,"failed":0},
"created":false
}
上面代碼中,我們將原始數據從"資料庫管理"改成"資料庫管理,軟體開發"。 返回結果裡面,有幾個欄位發生了變化。
"_version" : 2,
"result" : "updated",
"created" : false
可以看到,記錄的 Id 沒變,但是版本(version)從1變成2,操作類型(result)從created變成updated,created欄位變成false,因為這次不是新建記錄。
六、數據查詢
6.1 返回所有記錄
使用 GET 方法,直接請求/Index/Type/_search,就會返回所有記錄。
$ curl "localhost:9200/accounts/person/_search"
{
"took":2,
"timed_out":false,
"_shards":{"total":5,"successful":5,"failed":0},
"hits":{
"total":2,
"max_score":1.0,
"hits":[
{
"_index":"accounts",
"_type":"person",
"_id":"AV3qGfrC6jMbsbXb6k1p",
"_score":1.0,
"_source": {
"user": "李四",
"title": "工程師",
"desc": "系統管理"
}
},
{
"_index":"accounts",
"_type":"person",
"_id":"1",
"_score":1.0,
"_source": {
"user" : "張三",
"title" : "工程師",
"desc" : "資料庫管理,軟體開發"
}
}
]
}
}
上面代碼中,返回結果的 took欄位表示該操作的耗時(單位為毫秒),timed_out欄位表示是否超時,hits欄位表示命中的記錄,裡面子欄位的含義如下。
total:返回記錄數,本例是2條。
max_score:最高的匹配程度,本例是1.0。
hits:返回的記錄組成的數組。
返回的記錄中,每條記錄都有一個_score欄位,表示匹配的程序,默認是按照這個欄位降序排列。
6.2 全文搜索
Elastic 的查詢非常特別,使用自己的查詢語法,要求 GET 請求帶有數據體。
$ curl "localhost:9200/accounts/person/_search" -d "
{
"query" : { "match" : { "desc" : "軟體" }}
}"
上面代碼使用 Match 查詢,指定的匹配條件是desc欄位裡面包含"軟體"這個詞。返回結果如下。
{
"took":3,
"timed_out":false,
"_shards":{"total":5,"successful":5,"failed":0},
"hits":{
"total":1,
"max_score":0.28582606,
"hits":[
{
"_index":"accounts",
"_type":"person",
"_id":"1",
"_score":0.28582606,
"_source": {
"user" : "張三",
"title" : "工程師",
"desc" : "資料庫管理,軟體開發"
}
}
]
}
}
Elastic 默認一次返回10條結果,可以通過size欄位改變這個設置。
$ curl "localhost:9200/accounts/person/_search" -d "
{
"query" : { "match" : { "desc" : "管理" }},
"size": 1
}"
上面代碼指定,每次只返回一條結果。
還可以通過from欄位,指定位移。
$ curl "localhost:9200/accounts/person/_search" -d "
{
"query" : { "match" : { "desc" : "管理" }},
"from": 1,
"size": 1
}"
上面代碼指定,從位置1開始(默認是從位置0開始),只返回一條結果。
6.3 邏輯運算
如果有多個搜索關鍵字, Elastic 認為它們是or關係。
$ curl "localhost:9200/accounts/person/_search" -d "
{
"query" : { "match" : { "desc" : "軟體 系統" }}
}"
上面代碼搜索的是軟體 or 系統。
如果要執行多個關鍵詞的and搜索,必須使用布爾查詢。
$ curl "localhost:9200/accounts/person/_search" -d "
{
"query": {
"bool": {
"must": [
{ "match": { "desc": "軟體" } },
{ "match": { "desc": "系統" } }
]
}
}
}"
七、參考鏈接
ElasticSearch 官方手冊
A Practical Introduction to Elasticsearch
via:http://www.ruanyifeng.com/blog/2017/08/elasticsearch.html
※想要成為軟體開發中的王者,需要明白的 21 條準則
※詳述 PO VO BO DTO DAO 和 POJO 的概念及區別
※文件各種上傳,離不開的表單
※關於技術趨勢,寫給奮鬥中的程序員們
TAG:全棧開發者中心 |
※實時搜索引擎Elasticsearch
※使用Docker和Elasticsearch搭建全文本搜索引擎應用
※快速查找3D asset,Unity推出3D內容搜索引擎Visual Search
※Google 搜索引擎停止支持 Windows Phone
※Chrome添加DuckDuckGo搜索引擎
※Creative Commons搜索引擎正式上線 可檢索超3億張圖片
※繼學術搜索後,谷歌再次推出資料庫搜索引擎Dataset Search
※WeWork 收購搜索引擎優化和市場營銷公司 Conductor
※網路日誌搜索引擎——NetSearch
※MESON發布新搜索引擎Heymesh,Magic Leap 404頁面隱藏神秘彩蛋
※谷歌付蘋果數十億,讓其成為iPhone和Mac產品Safari默認搜索引擎
※三星披露收購人工智慧搜索引擎 Kngine,Bixby 背後不止 Viv Labs
※我為什麼反對 Google 拍賣 Android 搜索引擎選項?
※不懂Google Featured Snippets?搜索引擎C位出道的機會別再錯過了!
※谷歌支付蘋果數十億讓其成為iPhone和Mac產品Safari瀏覽器默認搜索引擎
※搜索引擎原理:Spider
※Google 證實其已終止針對中國的搜索引擎項目 Dragonfly
※三星收購AI搜索引擎Kngine 改進語音助手Bixby
※三星收購AI搜索引擎公司Kngine 提升Bixby性能
※三星收購AI搜索引擎公司Kngine,以改進語音助手Bixby