保留ElasticSearch查询中的术语顺序

Art*_*tur 6 elasticsearch

在ElasticSearch中是否可以形成一个保留条款顺序的查询?

一个简单的例子是使用标准分析器索引这些文档:

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

我可以查询+you +search,这将返回所有文件,包括第三个.

如果我只想检索具有此特定顺序条款的文档,该怎么办?我可以形成一个可以帮我的查询吗?

考虑到短语可以简单地引用文本:( "you know"检索第一和第二个文档),我觉得应该有一种方法来保留不相邻的多个术语的顺序.

在上面的简单示例中,我可以使用邻近搜索,但这并不包括更复杂的情况.

Dan*_*ery 11

您可以使用span_near查询,它有一个in_order参数.

{
    "query": {
        "span_near": {
            "clauses": [
                {
                    "span_term": {
                        "field": "you"
                    }
                },
                {
                    "span_term": {
                        "field": "search"
                    }
                }
            ],
            "slop": 2,
            "in_order": true
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


And*_*fan 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": {}
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

为了使脚本本身更具可读性,我在这里用缩进重写:

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;
Run Code Online (Sandbox Code Playgroud)

上面是一个搜索"hello world"的搜索,其中一个slop为5,在上面的文档中将匹配所有这些.但脚本过滤器将确保单词"hello"中文档中的位置低于单词"world"中文档中的位置.通过这种方式,无论我们在查询中设置了多少污点,这些位置是一个接一个的事实确保了订单.

这是文档中的部分,它阐述了上面脚本中使用的内容.