【问题标题】:Is there a way to relate a score to a particular field(s) in full text index有没有办法将分数与全文索引中的特定字段相关联
【发布时间】:2018-03-16 19:22:15
【问题描述】:

我有一个基于多个字段的全文索引,目前所有字段的默认权重均为 1。 现在我想从全文索引中搜索特定字段。因此,我正在考虑为不同的字段赋予不同的权重,并以某种方式将分数映射到字段,以便我可以根据分数进行过滤,从而从多个字段中过滤出特定的字段。但是看看分数计算是如何完成的 (https://github.com/mongodb/mongo/blob/master/src/mongo/db/fts/fts_spec.cpp),正确地获得分数和字段的映射似乎不是那么简单,或者可能是不可能的。

db.collection.createIndex({
        Name: "text",
        Line: "text",
        City: "text",
        State: "text",
        Zip: "text",

    },   {
     weights: {
       Name: 16,
       Line:8,
       City: 4,
       State: 2,
       Zip: 1,
     },
     name: "TextIndex"
   })

有没有人做过类似的事情,可以指点一下吗?

【问题讨论】:

  • 权重会影响所有搜索。如果您需要索引中的所有字段,并且希望将搜索限制在特定查询中的特定字段,最好使用文本搜索 + 正则表达式进行聚合。
  • @AlexBlex 我已经有一个正则表达式,但速度很慢。于是想优化。不确定权重是什么意思会影响所有搜索。由于每个字段的权重不同,因此每个字段匹配对分数的贡献也不同,对吧?所以我正在寻找一个解决方案,以确定哪些字段对分数有贡献。
  • 这与 现在我想从全文索引中搜索特定字段。 我明白了,因为您需要限制搜索,例如到NameLine,这样如果匹配的单词仅在City 字段中,则不应返回该文档。它是否准确地描述了需求?如果是这样,重量将无济于事。它们影响该领域的重要性,即希望您按相关性排序的文档顺序。
  • @AlexBlex 是的,你没看错:我的要求。如果我必须只搜索单个字段(名称),我相当确定我可以让它工作。但我一直在寻找一种可能性,如果我能以某种方式获得通用解决方案。
  • 我想知道怎么做?您是否忘记在问题中提及使之成为可能的内容?通常情况下,分数介于 0 和权重之间。如果分数介于 weight 和 2*weight 之间,您的方法会起作用,但事实并非如此。对于在很长的Name 中找到的单词,即使该字段的权重为 16,基数为 0 时,其权重总是

标签: mongodb full-text-search


【解决方案1】:

Mongodb 对全文搜索的支持有限。最重要的限制记录在https://docs.mongodb.com/manual/core/index-text/#restrictions

由于字符串的长度有限,您可以估计最小分数并使用权重并按分数范围过滤,例如:

db.collection.createIndex({
    Name: "text",
    Line: "text",
    City: "text",
    State: "text",
    Zip: "text",

},   {
 weights: {
   Name: 10000,
   Line:1000,
   City: 100,
   State: 10,
   Zip: 1,
 },
 name: "TextIndex"
})

仅在 LineState 中搜索:

db.collection.aggregate([
    {$match: {$text:{$search: serach_string}}}, 
    {$addFields: { score: { $meta: "textScore" } } },
    {$match: {$or:[
      // 1.01 - is the minimal score for State, higher than weight of Zip
      {score:{$gte: 1.01, $lte: 10}}, 
      // 100.01 - is the minimal score for Line, higher than total weight of Zip, State, and City
      // 1010 - is the summary weight of State and Line
      {score:{$gte: 100.01, $lte: 1010}}
    ]}}
])

对于任意长度的字符串,最好的方法是结合文本搜索和正则表达式:

db.collection.find({$and:[
    {$text:{$search: serach_string}}, 
    {$or:[{State:/regex/i}, {Line:/regex/i}]}
]})

您需要标记serach_string 并获取词干来构建正则表达式。在一般情况下,它不会为您提供与仅为 2 个字段构建的索引上的文本搜索相同的结果,因为正则表达式对排序规则一无所知。


最后,您可以在隐藏的辅助节点上拥有多个文本索引。它将为您提供最佳结果,但需要副本集中的其他成员。参见例如Different indexes on different replica set members了解详情。

【讨论】:

  • 如果您能将公式用于计算具有给定权重的字段的最低分数,那将会很有帮助。谢谢。
  • 我怀疑有一个。它实际上取决于文档中的字符串和查询——两者都会随着时间而变化。我有没有提到你需要研究两者,而且它不是 100% 可靠的?在一般情况下,人们总是可以制作一个足够长的 search_string 以获得极低的分数,这将低于范围边界。
  • 你在评论中有这个 // 2 - 是状态的最低分数,高于 Zip 的权重。所以想知道你是怎么得到这个号码的
  • 这只是一个例子,因此评论。你必须找到合适的号码。 2 只是表示它必须大于Zip 的权重。我已将其更改为 1.01 以使其更清晰。
  • 好的。我真的很希望能得到一些对某人有用的硬拒绝:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多