2014-10-29 84 views
3

ElasticSearch中可能會形成一個查詢來保留術語的順序嗎?保留ElasticSearch查詢中的術語順序

一個簡單的例子是具有這些文檔進行索引使用標準分析儀:

  1. 你知道搜索
  2. 你知道搜索
  3. 知道搜索你

我可以查詢+you +search這將返回所有文檔,包括第三個文檔。

如果我只想檢索具有此特定順序條款的文檔,該怎麼辦?我可以形成一個查詢來爲我做這件事嗎?

考慮到短語可能通過簡單引用文本:"you know"(檢索第1和第2個文檔),我覺得應該有一種方法來保留不相鄰的多個詞語的順序。

在上面的簡單示例中,我可以使用鄰近搜索,但這不包括更復雜的情況。

回答

7

您可以使用span_near查詢,它有一個in_order參數。

{ 
    "query": { 
     "span_near": { 
      "clauses": [ 
       { 
        "span_term": { 
         "field": "you" 
        } 
       }, 
       { 
        "span_term": { 
         "field": "search" 
        } 
       } 
      ], 
      "slop": 2, 
      "in_order": true 
     } 
    } 
} 
+0

想要添加一些帶通配符的query_string,這個必須更好! – 2014-10-30 21:49:15

+0

非常感謝。它確實有效。雖然我希望有一種方法可以做到,但沒有指定坡度值,但我知道我可以通過設置坡度這麼高的價值來作弊。 – Artur 2014-10-31 10:39:32

1

這正是match_phrase查詢(請參閱here)所做的。

它檢查條款的位置,在他們的存在之上。

例如,這些文件:

POST test/values 
{ 
    "test": "Hello World" 
} 

POST test/values 
{ 
    "test": "Hello nice World" 
} 

POST test/values 
{ 
    "test": "World, I don't say hello" 
} 

將全部使用基本match查詢發現:

POST test/_search 
{ 
    "query": { 
    "match": { 
     "test": "Hello World" 
    } 
    } 
} 

但使用match_phrase,只有第一個文件將被退回:

POST test/_search 
{ 
    "query": { 
    "match_phrase": { 
     "test": "Hello World" 
    } 
    } 
} 

{ 
    ... 
    "hits": { 
     "total": 1, 
     "max_score": 2.3953633, 
     "hits": [ 
     { 
      "_index": "test", 
      "_type": "values", 
      "_id": "qFZAKYOTQh2AuqplLQdHcA", 
      "_score": 2.3953633, 
      "_source": { 
       "test": "Hello World" 
      } 
     } 
     ] 
    } 
} 

在你的情況下,你想接受有您的條款之間有一段距離。這可以通過slop參數,這表明你允許多遠,你的條件是一個從另一個來實現:

POST test/_search 
{ 
    "query": { 
    "match": { 
     "test": { 
     "query": "Hello world", 
     "slop":1, 
     "type": "phrase" 
     } 
    } 
    } 
} 

利用這最後的要求,你會發現第二個文檔太:

{ 
    ... 
    "hits": { 
     "total": 2, 
     "max_score": 0.38356602, 
     "hits": [ 
     { 
      "_index": "test", 
      "_type": "values", 
      "_id": "7mhBJgm5QaO2_aXOrTB_BA", 
      "_score": 0.38356602, 
      "_source": { 
       "test": "Hello World" 
      } 
     }, 
     { 
      "_index": "test", 
      "_type": "values", 
      "_id": "VKdUJSZFQNCFrxKk_hWz4A", 
      "_score": 0.2169777, 
      "_source": { 
       "test": "Hello nice World" 
      } 
     } 
     ] 
    } 
} 

你可以在definitive guide中找到關於此用例的完整章節。

+0

在OP的例子中,他也需要使用slop值。 – 2014-10-29 15:57:41

+0

確實!回答更新,謝謝丹。 – ThomasC 2014-10-29 16:10:43

+0

如果單詞之間的距離是任意的,那該怎麼辦? '你好一個兩個... n詞條世界'?如果坡度很高,它最終會匹配「世界,我也不打招呼」。 坡度1會匹配「世界你好」,對吧? – Artur 2014-10-29 16:25:57

6

短語匹配不能確保順序;-)。例如,如果您指定了足夠的斜坡(例如2),則「hello world」將匹配「world hello」。但這不一定是壞事,因爲如果兩個詞彼此「接近」並且它們的順序無關,那麼通常搜索就更具相關性。我不認爲這個特徵的作者想到了匹配1000個單詞的單詞。

有一個解決方案,我可以找到保持順序,但不簡單:使用腳本。這裏有一個例子:

POST /my_index/my_type/_bulk 
{ "index": { "_id": 1 }} 
{ "title": "hello world" } 
{ "index": { "_id": 2 }} 
{ "title": "world hello" } 
{ "index": { "_id": 3 }} 
{ "title": "hello term1 term2 term3 term4 world" } 

POST my_index/_search 
{ 
    "query": { 
    "filtered": { 
     "query": { 
     "match": { 
      "title": { 
      "query": "hello world", 
      "slop": 5, 
      "type": "phrase" 
      } 
     } 
     }, 
     "filter": { 
     "script": { 
      "script": "term1Pos=0;term2Pos=0;term1Info = _index['title'].get('hello',_POSITIONS);term2Info = _index['title'].get('world',_POSITIONS); for(pos in term1Info){term1Pos=pos.position;}; for(pos in term2Info){term2Pos=pos.position;}; return term1Pos<term2Pos;", 
      "params": {} 
     } 
     } 
    } 
    } 
} 

使腳本本身更具可讀性,我重寫在這裏與壓痕:

term1Pos = 0; 
term2Pos = 0; 
term1Info = _index['title'].get('hello',_POSITIONS); 
term2Info = _index['title'].get('world',_POSITIONS); 
for(pos in term1Info) { 
    term1Pos = pos.position; 
}; 
for(pos in term2Info) { 
    term2Pos = pos.position; 
}; 
return term1Pos < term2Pos; 

上面就是爲5的斜率爲「Hello World」的搜索查詢其在上面的文檔中將匹配所有這些文檔。但是腳本過濾器將確保單詞「hello」的文檔中的位置低於單詞「world」中的文檔中的位置。通過這種方式,無論我們在查詢中設置了多少滑移,這些位置都是一個接一個地確保訂單。

這是section in the documentation,它闡明瞭上面腳本中使用的東西。

+0

+ +1努力和解決方案。我仍然希望有一個更優雅/少hacky解決我的問題;) – Artur 2014-10-29 17:13:05

+0

我很好奇,以及其他一些解決方案。這是我能想到的唯一方法。 – 2014-10-29 17:21:48

+0

其實已經試過運行它我得到似乎是由'GroovyScriptExecutionException [MissingPropertyException [沒有這樣的屬性:標題的類:Script4]]引起的'QueryPhaseExecutionException';'我正在運行v1.4測試版。 – Artur 2014-10-30 10:47:40