這篇文章有點深度,可能需要一些Lucene或者全文檢索的背景。由於我也很久沒有看過Lucene了,有些地方理解的不對還請多多指正。 更多內容 "還請參考整理的ELK教程" 關於Term Vectors 額,對於這個專業辭彙,暫且就叫做詞條向量吧,因為實在想不出什麼標準的翻譯。說的土一點,也可以理解為 ...
這篇文章有點深度,可能需要一些Lucene或者全文檢索的背景。由於我也很久沒有看過Lucene了,有些地方理解的不對還請多多指正。
更多內容還請參考整理的ELK教程
關於Term Vectors
額,對於這個專業辭彙,暫且就叫做詞條向量吧,因為實在想不出什麼標準的翻譯。說的土一點,也可以理解為關於詞的一些統計信息
。再說的通俗點,如果想進行全文檢索,即從一個詞搜索與它相關的文檔,總得有個什麼記錄的信息吧!這就是Term Vectors。
為了不幹擾正常的理解,後續就都直接稱呼英文的名字吧!免得誤導...
先不看這篇文章,如果想要記錄全文檢索的信息,大家設想一下我們都需要什麼內容,就拿"hello world! hello everybody!"
來舉例。
- 首先就是這句話都有什麼詞,"hello","world","everybody"
- 然後是這些詞關聯的文檔,因為有可能不止上面這一句話。
- 最後就是詞在文檔中的位置,比如hello,出現了兩次,就需要記錄兩份位置信息。
關於TermVector在Lucene中的概念,可以參考網路中的一篇文章
使用_termvectors查詢詞條向量
在Elasticsearch中可以使用_termvectors查詢一個文檔中詞條相關的信息。這個文檔可能是es中存儲的,也可能是用戶直接在請求體中自定義的。這個方法預設是一個實時的統計信息。
常見的語法如:
curl -XGET 'http://localhost:9200/twitter/tweet/1/_termvectors?pretty=true'
也可以指定某個欄位,返回這個欄位的信息:
curl -XGET 'http://localhost:9200/twitter/tweet/1/_termvectors?fields=text,...'
註意,在Elasticsearch中2.0之前都是使用_termvector,之後都是使用的_termvectors。
返回的信息
使用上面的請求,會返回詞條相關的信息:
- 詞條的信息,比如position位置、start_offset開始的偏移值、end_offset結束的偏移值、詞條的payLoads(這個主要用於自定義欄位的權重)
- 詞條統計,doc_freq、ttf該詞出現的次數、term_freq詞的頻率
- 欄位統計,包含sum_doc_freq該欄位中詞的數量(去掉重覆的數目)、sum_ttf文檔中詞的數量(包含重覆的數目)、doc_count涉及的文檔數等等。
預設會返回詞條的信息和統計,而不會返回欄位的統計。
另外,預設這些統計信息是基於分片的,可以設置dfs為true,返回全部分片的信息,但是會有一定的性能問題,所以不推薦使用。還可以使用field欄位對返回的統計信息的欄位進行過濾,只返回感興趣的那部分內容。
例子1:返回存儲的Term Vectors信息
首先需要定義一下映射的信息:
curl -s -XPUT 'http://localhost:9200/twitter/' -d '{
"mappings": {
"tweet": {
"properties": {
"text": {
"type": "string",
"term_vector": "with_positions_offsets_payloads",
"store" : true,
"analyzer" : "fulltext_analyzer"
},
"fullname": {
"type": "string",
"term_vector": "with_positions_offsets_payloads",
"analyzer" : "fulltext_analyzer"
}
}
}
},
"settings" : {
"index" : {
"number_of_shards" : 1,
"number_of_replicas" : 0
},
"analysis": {
"analyzer": {
"fulltext_analyzer": {
"type": "custom",
"tokenizer": "whitespace",
"filter": [
"lowercase",
"type_as_payload"
]
}
}
}
}
}'
然後插入兩條數據:
curl -XPUT 'http://localhost:9200/twitter/tweet/1?pretty=true' -d '{
"fullname" : "John Doe",
"text" : "twitter test test test "
}'
curl -XPUT 'http://localhost:9200/twitter/tweet/2?pretty=true' -d '{
"fullname" : "Jane Doe",
"text" : "Another twitter test ..."
}'
接下來查詢一下文檔1的Term Vectors信息:
curl -XGET 'http://localhost:9200/twitter/tweet/1/_termvectors?pretty=true' -d '{
"fields" : ["text"],
"offsets" : true,
"payloads" : true,
"positions" : true,
"term_statistics" : true,
"field_statistics" : true
}'
可以得到下麵的結果:
{
"_id": "1",
"_index": "twitter",
"_type": "tweet",
"_version": 1,
"found": true,
"term_vectors": {
"text": {
"field_statistics": {
"doc_count": 2,
"sum_doc_freq": 6,
"sum_ttf": 8
},
"terms": {
"test": {
"doc_freq": 2,
"term_freq": 3,
"tokens": [
{
"end_offset": 12,
"payload": "d29yZA==",
"position": 1,
"start_offset": 8
},
{
"end_offset": 17,
"payload": "d29yZA==",
"position": 2,
"start_offset": 13
},
{
"end_offset": 22,
"payload": "d29yZA==",
"position": 3,
"start_offset": 18
}
],
"ttf": 4
},
"twitter": {
"doc_freq": 2,
"term_freq": 1,
"tokens": [
{
"end_offset": 7,
"payload": "d29yZA==",
"position": 0,
"start_offset": 0
}
],
"ttf": 2
}
}
}
}
}
可以看到上面返回了詞條的統計信息,以及欄位的統計信息。
例子2:輕量級生成Term Vectors
雖然這個欄位不是顯示存儲的,但是仍然可以進行詞條向量的信息統計。因為ES可以在查詢的時候,從_source中分析出相應的內容。
curl -XGET 'http://localhost:9200/twitter/tweet/1/_termvectors?pretty=true' -d '{
"fields" : ["text", "some_field_without_term_vectors"],
"offsets" : true,
"positions" : true,
"term_statistics" : true,
"field_statistics" : true
}'
關於欄位的存儲於不存儲,可以簡單的理解為:
- 如果欄位存儲,在ES進行相關的查詢時,會直接從存儲的欄位讀取信息
- 如果欄位不存儲,ES會從_source中查詢分析,提取相應的部分。
由於每次讀取操作都是一次的IO,因此如果你不是只針對某個欄位、或者_source中的信息太多,那麼請優先不存儲該欄位,即從_source中獲取就好。
例子3:手動自定義的文檔統計
ES支持對一個用戶自定義的文檔進行分析,比如:
curl -XGET 'http://localhost:9200/twitter/tweet/_termvectors' -d '{
"doc" : {
"fullname" : "John Doe",
"text" : "twitter test test test"
}
}'
註意如果這個欄位沒有預先定義映射,那麼會按照預設的映射配置進行分析。
例子4:重新定義分析器
可以使用per_field_analyzer參數定義該欄位的分析器,這樣每個欄位都可以使用不同的分析器,分析其詞條向量的信息。如果這個欄位已經經過存儲,那麼會重新生成它的詞條向量,如:
curl -XGET 'http://localhost:9200/twitter/tweet/_termvectors' -d '{
"doc" : {
"fullname" : "John Doe",
"text" : "twitter test test test"
},
"fields": ["fullname"],
"per_field_analyzer" : {
"fullname": "keyword"
}
}'
會返回:
{
"_index": "twitter",
"_type": "tweet",
"_version": 0,
"found": true,
"term_vectors": {
"fullname": {
"field_statistics": {
"sum_doc_freq": 1,
"doc_count": 1,
"sum_ttf": 1
},
"terms": {
"John Doe": {
"term_freq": 1,
"tokens": [
{
"position": 0,
"start_offset": 0,
"end_offset": 8
}
]
}
}
}
}
}
例子5:欄位過濾器
在進行詞條向量的信息查詢時,可以根據自定義的過濾器,返回感興趣的信息。
常用的過濾器參數如:
- max_num_terms 最大的詞條數目
- min_term_freq 最小的詞頻,比如忽略那些在欄位中出現次數小於一定值的詞條。
- max_term_freq 最大的詞頻
- min_doc_freq 最小的文檔頻率,比如忽略那些在文檔中出現次數小於一定的值的詞條
- max_doc_freq 最大的文檔頻率
- min_word_length 忽略的詞的最小長度
- max_word_length 忽略的詞的最大長度
GET /imdb/movies/_termvectors
{
"doc": {
"plot": "When wealthy industrialist Tony Stark is forced to build an armored suit after a life-threatening incident, he ultimately decides to use its technology to fight against evil."
},
"term_statistics" : true,
"field_statistics" : true,
"dfs": true,
"positions": false,
"offsets": false,
"filter" : {
"max_num_terms" : 3,
"min_term_freq" : 1,
"min_doc_freq" : 1
}
}
會返回:
{
"_index": "imdb",
"_type": "movies",
"_version": 0,
"found": true,
"term_vectors": {
"plot": {
"field_statistics": {
"sum_doc_freq": 3384269,
"doc_count": 176214,
"sum_ttf": 3753460
},
"terms": {
"armored": {
"doc_freq": 27,
"ttf": 27,
"term_freq": 1,
"score": 9.74725
},
"industrialist": {
"doc_freq": 88,
"ttf": 88,
"term_freq": 1,
"score": 8.590818
},
"stark": {
"doc_freq": 44,
"ttf": 47,
"term_freq": 1,
"score": 9.272792
}
}
}
}
}