类似此查询编辑

类似此查询 (More Like This Query) 用于查找与给定文档集“类似”的文档。为此,MLT 会选择这些输入文档的一组代表性词条,使用这些词条形成查询,执行查询并返回结果。用户可以控制输入文档、如何选择词条以及如何形成查询。

最简单的用例是请求与提供的文本段落相似的文档。在这里,我们请求所有在“标题”和“描述”字段中包含类似于“从前”的文本的所有电影,并将所选词条的数量限制为 12 个。

response = client.search(
  body: {
    query: {
      more_like_this: {
        fields: [
          'title',
          'description'
        ],
        like: 'Once upon a time',
        min_term_freq: 1,
        max_query_terms: 12
      }
    }
  }
)
puts response
GET /_search
{
  "query": {
    "more_like_this" : {
      "fields" : ["title", "description"],
      "like" : "Once upon a time",
      "min_term_freq" : 1,
      "max_query_terms" : 12
    }
  }
}

更复杂的用例是将文本与索引中已存在的文档混合在一起。在这种情况下,指定文档的语法类似于多重获取 API中使用的语法。

response = client.search(
  body: {
    query: {
      more_like_this: {
        fields: [
          'title',
          'description'
        ],
        like: [
          {
            _index: 'imdb',
            _id: '1'
          },
          {
            _index: 'imdb',
            _id: '2'
          },
          'and potentially some more text here as well'
        ],
        min_term_freq: 1,
        max_query_terms: 12
      }
    }
  }
)
puts response
GET /_search
{
  "query": {
    "more_like_this": {
      "fields": [ "title", "description" ],
      "like": [
        {
          "_index": "imdb",
          "_id": "1"
        },
        {
          "_index": "imdb",
          "_id": "2"
        },
        "and potentially some more text here as well"
      ],
      "min_term_freq": 1,
      "max_query_terms": 12
    }
  }
}

最后,用户可以混合一些文本、一组选定的文档,还可以提供索引中不一定存在的文档。要提供索引中不存在的文档,语法类似于人工文档

response = client.search(
  body: {
    query: {
      more_like_this: {
        fields: [
          'name.first',
          'name.last'
        ],
        like: [
          {
            _index: 'marvel',
            doc: {
              name: {
                first: 'Ben',
                last: 'Grimm'
              },
              _doc: "You got no idea what I'd... what I'd give to be invisible."
            }
          },
          {
            _index: 'marvel',
            _id: '2'
          }
        ],
        min_term_freq: 1,
        max_query_terms: 12
      }
    }
  }
)
puts response
GET /_search
{
  "query": {
    "more_like_this": {
      "fields": [ "name.first", "name.last" ],
      "like": [
        {
          "_index": "marvel",
          "doc": {
            "name": {
              "first": "Ben",
              "last": "Grimm"
            },
            "_doc": "You got no idea what I'd... what I'd give to be invisible."
          }
        },
        {
          "_index": "marvel",
          "_id": "2"
        }
      ],
      "min_term_freq": 1,
      "max_query_terms": 12
    }
  }
}

工作原理编辑

假设我们想查找与给定输入文档类似的所有文档。显然,对于这种类型的查询,输入文档本身应该是最佳匹配。根据Lucene 评分公式,这主要是因为具有最高 tf-idf 的词条。因此,输入文档中具有最高 tf-idf 的词条可以很好地代表该文档,并且可以在析取查询(或 OR)中使用以检索类似的文档。MLT 查询只是从输入文档中提取文本,对其进行分析(通常使用字段中的相同分析器),然后选择具有最高 tf-idf 的前 K 个词条,以形成这些词条的析取查询。

要对其执行 MLT 的字段必须已建立索引,并且类型为 textkeyword。此外,当对文档使用 like 时,必须启用 _source,或者字段必须为 stored 或存储 term_vector。为了加快分析速度,在索引时存储词条向量可能会有所帮助。

例如,如果我们希望对“标题”和“tags.raw”字段执行 MLT,我们可以在索引时显式存储它们的 term_vector。我们仍然可以对“描述”和“标签”字段执行 MLT,因为默认情况下启用了 _source,但这些字段的分析速度不会加快。

response = client.indices.create(
  index: 'imdb',
  body: {
    mappings: {
      properties: {
        title: {
          type: 'text',
          term_vector: 'yes'
        },
        description: {
          type: 'text'
        },
        tags: {
          type: 'text',
          fields: {
            raw: {
              type: 'text',
              analyzer: 'keyword',
              term_vector: 'yes'
            }
          }
        }
      }
    }
  }
)
puts response
PUT /imdb
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "term_vector": "yes"
      },
      "description": {
        "type": "text"
      },
      "tags": {
        "type": "text",
        "fields": {
          "raw": {
            "type": "text",
            "analyzer": "keyword",
            "term_vector": "yes"
          }
        }
      }
    }
  }
}

参数编辑

唯一必需的参数是 like,所有其他参数都有合理的默认值。参数分为三种类型:一种用于指定文档输入,另一种用于词条选择,还有一种用于查询形成。

文档输入参数编辑

like

MLT 查询的唯一必需参数是 like,它遵循一种通用的语法,用户可以在其中指定自由格式文本和/或一个或多个文档(参见上面的示例)。指定文档的语法类似于多重获取 API中使用的语法。在指定文档时,除非在每个文档请求中覆盖,否则将从 fields 中获取文本。文本由字段中的分析器进行分析,但也可以覆盖。覆盖字段中分析器的语法类似于词条向量 APIper_field_analyzer 参数的语法。此外,为了提供索引中不一定存在的文档,还支持人工文档

unlike

unlike 参数与 like 结合使用,以便不选择在一组选定的文档中找到的词条。换句话说,我们可以请求 like: "Apple" 的文档,但 unlike: "cake crumble tree"。语法与 like 相同。

fields

要从中获取和分析文本的字段列表。默认为 index.query.default_field 索引设置,其默认值为 ** 值匹配所有符合词条级查询条件的字段,但不包括元数据字段。

词条选择参数编辑

max_query_terms

将选择的查询词条的最大数量。增加此值会提高准确性,但会降低查询执行速度。默认为 25

min_term_freq

低于此值的词条频率将被输入文档忽略。默认为 2

min_doc_freq

低于此值的文档频率将被输入文档忽略。默认为 5

max_doc_freq

高于此值的文档频率将被输入文档忽略。这在忽略停用词等高频词时非常有用。默认为无界限(Integer.MAX_VALUE,即 2^31-1 或 2147483647)。

min_word_length

低于此值的词条长度将被忽略。默认为 0

max_word_length

高于此值的词条长度将被忽略。默认为无界限(0)。

stop_words

停用词数组。此集合中的任何词都被视为“不感兴趣”并被忽略。如果分析器允许使用停用词,您可能需要告诉 MLT 显式忽略它们,因为出于文档相似性的目的,假设“停用词永远不感兴趣”似乎是合理的。

analyzer

用于分析自由格式文本的分析器。默认为与 fields 中的第一个字段关联的分析器。

查询形成参数编辑

minimum_should_match

在形成析取查询后,此参数控制必须匹配的词条数量。语法与minimum should match相同。(默认为 "30%")。

fail_on_unsupported_field

控制如果任何指定的字段不是受支持的类型(textkeyword),查询是否应该失败(抛出异常)。将其设置为 false 以忽略该字段并继续处理。默认为 true

boost_terms

形成的查询中的每个词条都可以通过其 tf-idf 分数进一步提升。这将设置使用此功能时要使用的提升因子。默认为停用(0)。任何其他正值都会使用给定的提升因子激活词条提升。

include

指定输入文档是否也应包含在返回的搜索结果中。默认为 false

boost

设置整个查询的提升值。默认为 1.0

替代方案编辑

要更好地控制类似文档的查询构造,值得考虑编写自定义客户端代码,将示例文档中的选定词条组装到具有所需设置的布尔查询中。more_like_this 中从一段文本中选择“有趣”词的逻辑也可以通过词条向量 API访问。例如,使用词条向量 API,可以向用户呈现文档文本中找到的主题关键词选择,允许他们选择感兴趣的词进行深入研究,而不是使用 more_like_this 使用的更“黑盒”的匹配方法。