標簽: search
elasticsearch 是一款非常強大的搜索開源搜索和分析軟件,高擴展高可用。
最新版本 1.7.2
搜索很強大,結合中文分詞,可以高效的檢索數據,給出符合查詢條件的數據,并排序賦予權重得分。
本篇只是入門級講解,大部分常用的功能基本涉及到了。
elasticsearch
是一款非常成熟的產品,如果需要更深層次的理解,需要詳細閱讀 官方文檔 。
目前狀況
雖然 elasticsearch
很強大,但是數據需要自己組織結構并導入。1.5
之前的版本支持 river
插件,可以通過插件直接從數據庫同步數據到 elasticsearch
中,但是目前版本已經 不推薦數據導入插件,所以需要自己寫 數據同步模塊。
中文分詞 可以使用,該插件支持實時更新熱詞,并且可以配置不同的分詞策略。
elasticsearch
基于 java
開發,運行需要安裝 java
環境。接口為 Restful
風格,實際使用時可以按照 CURD
的原則使用相應的 Http
協議。
默認配置綁定 localhost
,端口 9200
。
數據結構
數據存儲結構為 /{index}/{type}/{id}
,使用三級結構保存數據,原始數據保存為 JSON
。
例如:
PUT /index/test/1
{ "title": "最新電影" }
GET /index/test/1
{
"_index": "index",
"_type": "test",
"_id": "1",
"_version": 1,
"found": true,
"_source": {
"title": "最新電影"
}
}
原始文檔存放在 _source
下,并且存儲的數據添加了其他 MetaData
信息 _index
_type
_id
_version
,再次使用 PUT
可以更新文檔,使 _version
變為 2
。
數據導入
數據導入可以通過 Post
來完成。
1. 建立Index
建立一個普通的 _index
,不用傳任何參數 :
PUT http://localhost:9200/test
// 返回
{
"acknowledged": true
}
如果需要使用 Analysis
(語句分詞分析) ,則可以設置詳細的 _index
:
PUT http://localhost:9200/test
{
"settings": {
"refresh_interval": "5s",
"number_of_shards" : 1, // 一個主節點,默認5
"number_of_replicas" : 0 // 0個副本,后面可以加,默認1
},
"mappings": {
"_default_":{
"_all": { "enabled": false } // 關閉_all字段,因為我們只搜索title字段
},
"resource": { // 這個是 _type
"dynamic": false, // 關閉“動態修改索引”
"properties": {
"title": { // 表明對title字段進行分詞分析
"type": "string",
"index": "analyzed",
"fields": { // elasticsearch可以識別語言
"cn": { // 中文使用中文分詞
"type": "string",
"analyzer": "ik_smart"
},
"en": { // 英文使用英文分詞
"type": "string",
"analyzer": "english"
}
}
}
}
}
}
}
然后向上述 _index(test)
下導入數據:
POST /test/resource/ { "title": "周星馳" } // 這種會自動生成id
PUT /test/resource/1?op_type=create { "title": "周星馳" }
PUT /test/resource/1/_create { "title": "周星馳" }
上述的第一種方式會自動生成 _id
。
POST /_bulk or /test/_bulk or /test/resource/_bulk
{ "create": { "_index": "test", "_type": "resource", "_id": 1 } }
{ "title": "周星馳最新電影" }
{ "create": { "_index": "test", "_type": "resource", "_id": 2 } }
{ "title": "周星馳最好看的新電影" }
{ "create": { "_index": "test", "_type": "resource", "_id": 3 } }
{ "title": "周星馳最新電影,最好,新電影" }
{ "create": { "_index": "test", "_type": "resource", "_id": 4 } }
{ "title": "最最最最好的新新新新電影" }
{ "create": { "_index": "test", "_type": "resource", "_id": 5 } }
{ "title": "I'm not happy about the foxes" }
也可以將 /_bulk
提交的內容放入一個文本(文件末尾必須有一空行 \n
)
curl -s -XPOST localhost:9200/_bulk --data-binary "@requests"
// 已經存在會報錯
{
"error" : "DocumentAlreadyExistsException[[website][4] [blog][123]:
document already exists]",
"status" : 409
}
數據檢索
Retrieving 檢索文檔
可以使用 Head
判斷是否存在
HEAD /{index}/{type}/{id}
可以直接檢索到 id
一級,精確獲取文檔。
// pretty會格式化JSON
GET /{index}/{type}/{id}[?pretty][&_source=field1,field...]
_source命令可以精確檢索字段
可以使用 _search
命令:
GET /{index}/_search or /{index}/{type}/_search
// 返回示例
{
"took": 1, // 耗費毫秒數
"timed_out": false, // 可以在命令中設置?timeout=10ms
"_shards": { // 分區
"total": 5,
"successful": 5,
"failed": 0
},
"hits": { // 所有文檔
"total": 2,
"max_score": 1,
"hits": [ // 所有文檔
{
"_index": "test",
"_type": "resource",
"_id": 1,
"_score": 1,
"_source": {
"title": "周星馳"
}
},
...
]
}
}
如果開啟了 Analysis
,使用 multi_match
則可以按關鍵字(分詞)進行搜索,返回結果按 _score
來排序。
POST /{index}/{type}/_search
{
"query": {
"multi_match": {
"type": "most_fields",
"query": "周星馳最新電影fox",
"fields": ["title", "title.cn", "title.en"]
}
}
}
// 返回示例
{
"took": 7,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"hits": {
"total": 5,
"max_score": 1.4102149,
"hits": [
{
"_index": "index",
"_type": "test",
"_id": "1",
"_score": 1.4102149,
"_source": {
"title": "周星馳最新電影"
}
},
{
"_index": "index",
"_type": "test",
"_id": "3",
"_score": 1.1354887,
"_source": {
"title": "周星馳最新電影,最好,新電影"
}
},
{
"_index": "index",
"_type": "test",
"_id": "2",
"_score": 1.0024924,
"_source": {
"title": "周星馳最好看的新電影"
}
},
{
"_index": "index",
"_type": "test",
"_id": "4",
"_score": 0.31740457,
"_source": {
"title": "最最最最好的新新新新電影"
}
},
{
"_index": "index",
"_type": "test",
"_id": "5",
"_score": 0.013072087,
"_source": {
"title": "I'm not happy about the foxes"
}
}
]
}
}
還可以加上 分頁,高亮以及最小匹配度:
POST /{index}/{type}/_search
{
"query": {
"multi_match": {
"type": "most_fields", // 搜索使用的模式
"query": "周星馳最新電影fox",
"fields": [ "title", "title.cn", "title.en" ], // 設置搜索的范圍
"minimum_should_match": "20%" // 最小匹配度
}
},
"from": 0,
"size": 10,
"highlight" : {
"pre_tags" : ["<strong>"],
"post_tags" : ["</strong>"],
"fields" : {
"title" : {},
"title.cn" : {},
"title.en" : {}
}
}
}
// 返回
{
"took": 13,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"hits": {
"total": 5,
"max_score": 1.1782398,
"hits": [
{
"_index": "test",
"_type": "resource",
"_id": "1",
"_score": 1.1782398,
"_source": {
"title": "周星馳最新電影"
},
"highlight": {
"title": [
"<strong>周</strong><strong>星</strong><strong>馳</strong><strong>最</strong><strong>新</strong><strong>電</strong><strong>影</strong>"
],
"title.cn": [
"<strong>周星馳</strong><strong>最新</strong><strong>電影</strong>"
],
"title.en": [
"<strong>周</strong><strong>星</strong><strong>馳</strong><strong>最</strong><strong>新</strong><strong>電</strong><strong>影</strong>"
]
}
},
{
"_index": "test",
"_type": "resource",
"_id": "3",
"_score": 0.9440402,
"_source": {
"title": "周星馳最新電影,最好,新電影"
},
"highlight": {
"title": [
"<strong>周</strong><strong>星</strong><strong>馳</strong><strong>最</strong><strong>新</strong><strong>電</strong><strong>影</strong>,<strong>最</strong>好,<strong>新</strong><strong>電</strong><strong>影</strong>"
],
"title.cn": [
"<strong>周星馳</strong><strong>最新</strong><strong>電影</strong>,最好,<strong>新</strong><strong>電影</strong>"
],
"title.en": [
"<strong>周</strong><strong>星</strong><strong>馳</strong><strong>最</strong><strong>新</strong><strong>電</strong><strong>影</strong>,<strong>最</strong>好,<strong>新</strong><strong>電</strong><strong>影</strong>"
]
}
},
{
"_index": "test",
"_type": "resource",
"_id": "2",
"_score": 0.8302629,
"_source": {
"title": "周星馳最好看的新電影"
},
"highlight": {
"title": [
"<strong>周</strong><strong>星</strong><strong>馳</strong><strong>最</strong>好看的<strong>新</strong><strong>電</strong><strong>影</strong>"
],
"title.cn": [
"<strong>周星馳</strong><strong>最</strong>好看的<strong>新</strong><strong>電影</strong>"
],
"title.en": [
"<strong>周</strong><strong>星</strong><strong>馳</strong><strong>最</strong>好看的<strong>新</strong><strong>電</strong><strong>影</strong>"
]
}
},
{
"_index": "test",
"_type": "resource",
"_id": "4",
"_score": 0.255055,
"_source": {
"title": "最最最最好的新新新新電影"
},
"highlight": {
"title": [
"<strong>最</strong><strong>最</strong><strong>最</strong><strong>最</strong>好的<strong>新</strong><strong>新</strong><strong>新</strong><strong>新</strong><strong>電</strong><strong>影</strong>"
],
"title.cn": [
"最最<strong>最</strong>最好的新新新新<strong>電影</strong>"
],
"title.en": [
"<strong>最</strong><strong>最</strong><strong>最</strong><strong>最</strong>好的<strong>新</strong><strong>新</strong><strong>新</strong><strong>新</strong><strong>電</strong><strong>影</strong>"
]
}
},
{
"_index": "test",
"_type": "resource",
"_id": "5",
"_score": 0.012243208,
"_source": {
"title": "I'm not happy about the foxes"
},
"highlight": {
"title.en": [
"I'm not happy about the <strong>foxes</strong>"
]
}
}
]
}
}
elasticsearch
雖然可以識別語言類型,但是可以看到,英文分詞對中文是每個字都區分開了,中文分詞則不支持英文。所以使用的時候需要注意。
在上述例子中, multi_match
使用了 most_fields
,表示匹配任何滿足條件的 field
,multi_match
支持如下幾種模式:
best_fields
默認模式,搜索任何field
,但是使用_score
是所有field
中最高的一項。most_fields
搜索任何field
,但是_score
是所有field
的和值。cross_fields
將所有field
看成是一個進行搜索。match_phrase
ormatch_phrase_prefix
兩個與best_fields
類似,但是會把fileds
拆開,變成多個queries
{
"multi_match" : {
"query": "quick brown f",
"type": "phrase_prefix",
"fields": [ "subject", "message" ]
}
}
// to
{
"dis_max": {
"queries": [
{ "match_phrase_prefix": { "subject": "quick brown f" }},
{ "match_phrase_prefix": { "message": "quick brown f" }}
]
}
}
刪除文檔
DELETE
用來刪除文檔。
不會立即刪除,只是標記刪除,在需要的時候再刪除。
DELETE /{index} 刪除整個index
DELETE /{index}/{type} 刪除type一級
DELETE /{index}/{type}/{id} 刪除具體的某個文檔
// 200
{
"found" : true,
"_index" : "x",
"_type" : "x",
"_id" : "x",
"_version" : 3
}
// 404
{
"found" : false,
"_index" : "x",
"_type" : "x",
"_id" : "x",
"_version" : 4
}
中文分詞
配置,使用配置1或者2
elasticsearch.yml
// 1
index:
analysis:
analyzer:
ik:
alias: [ik_analyzer]
type: org.elasticsearch.index.analysis.IkAnalyzerProvider
ik_max_word:
type: ik
use_smart: false
ik_smart:
type: ik
use_smart: true
// 2
index.analysis.analyzer.ik.type : "ik" // = ik_max_word
ik_max_word
會將文本做最細粒度的拆分,如
『中華人民共和國國歌』被拆分成
『中華人民共和國』
『中華人民』
...
『國歌』,會窮盡各種可能的組合
ik_smart
會做最粗粒度的拆分,如
『中華人民共和國國歌』拆分為
『中華人民共和國』
『國歌』
在之前的例子中已經使用到了這個分詞插件。