如何跨多个文本字段组合完成、建议和匹配短语?

RPM*_*984 6 elasticsearch

我一直在阅读有关 Elasticsearch建议器匹配短语前缀突出显示的内容,但我对使用哪种方法来解决我的问题感到有些困惑。

要求:我有一堆不同的文本字段,并且需要能够自动完成和自动建议所有这些字段,以及拼写错误。基本上是谷歌的工作方式。

在下面的谷歌快照中看到,当我们开始输入“Can”时,它会列出加拿大、加拿大等词。这是自动完成的。但是,它还会列出其他词,例如轮胎、帖子、帖子跟踪、冠状病毒等。这是自动建议。它在所有领域中搜索最相关的词。如果我们输入“canxad”,它也应该拼错提示相同的结果。

在此处输入图片说明

有人可以给我一些关于如何在一堆文本字段中实现上述功能的提示吗?

起初我试过这个:

GET /myindex/_search
{
  "query": {
    "match_phrase_prefix": {
      "myFieldThatIsCombinedViaCopyTo": "revis"
    }
  },
  "highlight": {
    "fields": {
      "*": {}
    },
    "require_field_match" : false
  }
}
Run Code Online (Sandbox Code Playgroud)

但它返回这样的亮点:

“在委员会成员提出的上述修改中,现在的修改者也是当事人”,

所以这不再是“前缀”了......

也试过这个:

GET /myindex/_search
{
  "query": {
    "multi_match": {
      "query": "revis",
      "fields": ["myFieldThatIsCombinedViaCopyTo"],
      "type": "phrase_prefix",
      "operator": "and"
    }
  },
  "highlight": {
    "fields": {
      "*": {}
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

但它仍然返回

“在委员会成员提出的上述修改中,现在的修改者也是当事人”,

注意:我有大约 5 个“文本”字段需要搜索。其中一个字段很长(1000 多个字)。如果我把事情分解成关键词,我就会失去这个词组。所以这就像我需要在组合文本字段中匹配短语前缀,但很模糊?

编辑 这是一个文档示例(一些字段被删除,内容被剪掉):

{
  "id" : 1,
  "respondent" : "Union of India",
  "caseContent" : "<snip>..against the Union of India, through the ...<snip>"
}
Run Code Online (Sandbox Code Playgroud)

正如@Vlad 所建议的,我试过这个:

POST /cases/_search
POST /cases/_search
{
  "suggest": {
    "respondent-suggest": {
      "prefix": "uni",
      "completion": {
        "field": "respondent.suggest",
        "skip_duplicates": true
      }
    },
    "caseContent-suggest": {
      "prefix": "uni",
      "completion": {
        "field": "caseContent.suggest",
        "skip_duplicates": true
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

返回这个:

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 0,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "suggest" : {
    "caseContent-suggest" : [
      {
        "text" : "uni",
        "offset" : 0,
        "length" : 3,
        "options" : [ ]
      }
    ],
    "respondent-suggest" : [
      {
        "text" : "uni",
        "offset" : 0,
        "length" : 3,
        "options" : [
          {
            "text" : "Union of India",
            "_index" : "cases",
            "_type" : "_doc",
            "_id" : "dI5hh3IBEqNFLVH6-aB9",
            "_score" : 1.0,
            "_ignored" : [
              "headNote.suggest"
            ],
            "_source" : {
              <snip>
            }
          }
        ]
      }
    ]
  }
}
Run Code Online (Sandbox Code Playgroud)

所以看起来它在respondent场上匹配,这很棒!但是,它在caseContent现场不匹配,即使文本(见上文)包含短语“反对印度联盟”......它不应该在那里匹配吗?还是因为文本是如何分解的?

Val*_*Val 4

由于您需要在每个字段上自动完成/建议,因此您需要在每个字段上而不是在该字段上运行建议查询copy_to。这样您就可以保证拥有正确的前缀。

copy_to字段非常适合在多个字段中搜索,但不适合自动建议/完成类型的查询。

这个想法是,对于每个字段,您应该有一个completion子字段,以便您可以获得每个字段的自动完成结果。

PUT index
{
  "mappings": {
    "properties": {
      "text1": {
        "type": "text",
        "fields": {
          "suggest": {
            "type": "completion"
          }
        }
      },
      "text2": {
        "type": "text",
        "fields": {
          "suggest": {
            "type": "completion"
          }
        }
      },
      "text3": {
        "type": "text",
        "fields": {
          "suggest": {
            "type": "completion"
          }
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

然后,您建议的查询将直接在所有子字段上运行:

POST index/_search?pretty
{
    "suggest": {
        "text1-suggest" : {
            "prefix" : "revis", 
            "completion" : { 
                "field" : "text1.suggest" 
            }
        },
        "text2-suggest" : {
            "prefix" : "revis", 
            "completion" : { 
                "field" : "text2.suggest" 
            }
        },
        "text3-suggest" : {
            "prefix" : "revis", 
            "completion" : { 
                "field" : "text3.suggest" 
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这负责自动完成/建议部分。对于拼写错误,建议查询还允许您指定fuzzy参数

更新

如果您需要对文本正文中的所有句子进行前缀搜索,则方法需要稍微改变一下。

下面的新映射在文本旁边创建一个新的完成字段。这个想法是将一个小的转换(即分割句子)应用于您要存储在完成字段中的内容。因此,首先创建索引映射,如下所示:

PUT index
{
  "mappings": {
    "properties": {
      "text1": {
        "type": "text",
      },
      "text1Suggest": {
        "type": "completion"
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

然后创建一个摄取管道,text1Suggest用该字段中的句子填充该text1字段:

PUT _ingest/pipeline/sentence
{
  "processors": [
    {
      "split": {
        "field": "text1",
        "target_field": "text1Suggest.input",
        "separator": "\\.\\s+"
      }
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

然后我们可以索引这样一个文档(仅text1动态构建作为完成字段的字段)

PUT test/_doc/1?pipeline=sentence
{
  "text1": "The crazy fox. The quick snail. John goes to the beach"
}
Run Code Online (Sandbox Code Playgroud)

索引的内容如下所示(您的text1字段+另一个针对句子前缀完成而优化的完成字段):

{
  "text1": "The crazy fox. The cat drinks milk. John goes to the beach",
  "text1Suggest": {
    "input": [
      "The crazy fox",
      "The cat drinks milk",
      "John goes to the beach"
    ]
  }
}
Run Code Online (Sandbox Code Playgroud)

最后,您可以搜索任何句子的前缀,下面我们搜索 John,您应该会得到建议:

POST test/_search?pretty
{
  "suggest": {
    "text1-suggest": {
      "prefix": "John",
      "completion": {
        "field": "text1Suggest"
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)