【问题标题】:Lucens best way to do "starts-with" queriesLucens 进行“开始”查询的最佳方式
【发布时间】:2013-02-21 15:17:11
【问题描述】:

我希望能够进行以下类型的查询:

要索引的数据包括(比方说)只有标题有趣的音乐视频。 我只是想对这些进行索引,然后为它们创建查询,这样,无论用户在查询中使用什么单词或单词,包含这些单词的文档都将按顺序在图块的开头返回,然后(在没有特别的顺序)由在标题的任何位置包含至少一个搜索词的文档。此外,所有这些都应该不区分大小写。

例子:

对于文档:

  • Video1Title = 海是蓝色的
  • Video2Title = 野生海洋
  • Video3Title = 野生海洋 随便
  • Video4Title = 海边随便

如果我搜索“海”,我想得到 ​​p>

  • “Video1Title = 海是蓝色的”

首先是所有其他标题中包含“sea”的文档,但不是在开头。

如果我搜索“Wild sea”我想得到

  • Video2Title = 野生海洋
  • Video3Title = 野生海洋 随便

首先是标题中包含“Wild”或“Sea”但没有“Wild Sea”作为标题前缀的所有其他文档。

如果我搜索“Seasi”,我什么都不想得到(我不关心关键字标记化和前缀查询)。

现在 AFAIKS,没有实际的方法可以告诉 Lucene“找到 word1 和 word2 等在位置 1 和 2 和 3 等位置的文档。”

有一些“变通方法”可以模拟这种行为:

  • 索引该字段两次。在field1 中,您将单词标记化(可能使用StandardAnalyzer),在field2 中,您将它们全部聚集成一个元素(使用KeywordAnalyzer)。然后,如果您搜索类似:

    +(field1:word1 word2 word3) (field2:"word1 word2 word3*")

有效地告诉Lucene“文档的标题中必须包含word1或word2或word3,而且那些匹配“title以>word1 word2 word3

  • 在索引字段时将“lucene_start_token”添加到字段的开头,以便 Video2Title = Wild sea 被索引为“title:lucene_start_token Wild sea”,其余的以此类推

然后进行如下查询:

+(title:sea) (title:"lucene_start_token sea")

并让 Lucene 返回标题中包含我的搜索词的所有文档,并对匹配“lucene_start_token+搜索词”的文档给予更高的分数

我的问题是,确实有更好的方法来做到这一点(也许使用PhraseQueryTerm position)?如果不是,以上哪一项在性能方面更好?

【问题讨论】:

    标签: lucene startswith


    【解决方案1】:

    您可以为此使用Lucene Payloads。您可以为字段值的每个术语提供自定义提升。

    因此,当您为标题编制索引时,您可以开始使用 3 的提升因子(例如):

    标题:野生|3.0 生物|2.5 蓝色|2.0 |1.5

    标题:海洋|3.0 生物|2.5

    以这种方式编制索引可以将最近的术语提升到标题的开头。

    使用这种方法的主要问题是您必须自己标记化并“手动”添加所有这些提升信息,因为分析器需要以这种方式构造的文本 (term1|1.1 term2|3.0 term3)。

    【讨论】:

    • 这是一个很好的方法。确实,与其他方法相比,它会使查询复杂化,但我认为它是最有效的(没有额外的字段,繁重的工作是在索引时完成的,而不是在查询时完成的)。我能看到的唯一潜在的失败是当你从一个已经很复杂的查询开始时。用这种方法添加的新查询来平衡这一点可能会很棘手。
    • 为什么不依赖职位并使用SpanFirstQuery 就像建议的here 一样?它完全符合您的要求吗?
    【解决方案2】:

    您可以做的是分别索引标题和每个标记,例如文本wild deep blue endless sea 将被索引为:

    title: wild deep blue endless sea
    t1: wild
    t2: deep
    t3: blue
    t4: endless
    t5: sea
    

    如果有人查询“wild deep”,查询将被重写为

    title:"wild deep" OR (t1:wild AND t2:deep)
    

    这样您将始终找到所有匹配的文档(如果它们匹配title),但匹配t1..tN 标记将使相关文档得分更高。

    【讨论】:

    • 谢谢,这是个好主意。这样,我只能在我想要的时候匹配整个单词(而不是我的 1 个额外字段,它是关键字分析然后用于前缀(以 * 结尾)查询,我永远不知道它是否匹配整个字与否在最后)。我只需要使用在标题字段上使用的相同分析器来获取所有标记,然后在单独的字段中重新索引每个标记。对? :)
    • 是的,你是对的——你必须使用同一个分析器。我应该在我的回答中提到这一点。
    • 这是一个很好的方法,比我自己发现的方法更好(在问题中提到)。您最终确实有很多字段,如果索引大小已经非常大(索引被更频繁地拆分和/或需要更多堆内存),这可能会导致问题。然而,对于可管理的索引大小,这种方法在实现的简单性和结果的准确性之间取得了很好的平衡。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多