【问题标题】:full Text Search within embedded document嵌入文档中的全文搜索
【发布时间】:2016-07-16 07:46:40
【问题描述】:

这是我的文档模式

"translation" : {
        "en" : {
            "name" : "brown fox",
            "description" : "the quick brown fox jumps over a lazy dog"
        },
        "it" : {
            "name" : "brown fox ",
            "description" : " the quick brown fox jumps over a lazy dog"
        },
        "fr" : {
            "name" : "renard brun ",
            "description" : " le renard brun rapide saute par-dessus un chien paresseux"
        },
        "de" : {
            "name" : "brown fox ",
            "description" : " the quick brown fox jumps over a lazy dog"
        },
        "es" : {
            "name" : "brown fox ",
            "description" : " el rápido zorro marrón salta sobre un perro perezoso"
        }
    },

现在我必须为上述文档添加文本索引。我怎样才能实现? 我已经在翻译中添加了文本索引,但这不起作用,因为名称和描述在语言前缀内(在对象内)。我还必须分别给出名称和描述的文本权重(文本分数)。即名称的文本分数为 5,描述的分数为 2。所以我不能给出通配符文本索引,即

{'$**': 'text'}

我也尝试使用'translation.en.name': 'text',但它不起作用,而且我的语言是动态的,所以这种情况的最佳解决方案是什么

任何帮助将不胜感激。

【问题讨论】:

  • 您考虑更改文档结构并将动态键设为字段值。 { "lang": "en", "name" : "brown fox", "description" : "the quick brown fox jumps over a lazy dog" }
  • @SSDMS 你能否详细说明如何使用多个语言来实现这一点,即“de”或“ru”的索引

标签: mongodb meteor full-text-search


【解决方案1】:

因为嵌入字段是动态的,所以最好的方法是修改架构,使translation 字段成为嵌入文档的数组。映射当前结构的这种模式的示例如下:

"translation": [    
    {
        "lang": "en",
        "name" : "brown fox",
        "description" : "the quick brown fox jumps over a lazy dog"
    },
    {
        "lang": "it",
        "name" : "brown fox ",
        "description" : " the quick brown fox jumps over a lazy dog"
    },
    {
        "lang": "fr",
        "name" : "renard brun ",
        "description" : " le renard brun rapide saute par-dessus un chien paresseux"
    },
    {
        "lang": "de",
        "name" : "brown fox ",
        "description" : " the quick brown fox jumps over a lazy dog"
    },
    {
        "lang": "es",
        "name" : "brown fox ",
        "description" : " el rápido zorro marrón salta sobre un perro perezoso"
    }
]

使用此架构,可以轻松地将文本索引应用于 namedescription 字段:

db.collection.createIndex(
    {
        "translation.name": "text",
        "translation.description": "text"
    }
)

至于修改架构,您需要使用允许您批量更新集合的 api,Bulk API 会为您完成。这些提供了更好的性能,因为您将以 1000 个批量向服务器发送操作,这为您提供了更好的性能,因为您不是将每个请求都发送到服务器,而是每 1000 个请求发送一次。

以下演示了这种方法,第一个示例使用 MongoDB 版本 >= 2.6 和

var bulk = db.collection.initializeUnorderedBulkOp(),
    counter = 0;

db.collection.find({ 
    "translation": { 
        "$exists": true, 
        "$not": { "$type": 4 } 
    } 
}).snapshot().forEach(function (doc) {
    var localization = Object.keys(doc.translation)
        .map(function (key){
            var obj = doc["translation"][key];
            obj["lang"] = key;
            return obj;
        });
    bulk.find({ "_id": doc._id }).updateOne({ 
        "$set": { "translation": localization }
    });

    counter++;
    if (counter % 1000 === 0) {
        bulk.execute(); // Execute per 1000 operations 
        // re-initialize every 1000 update statements
        bulk = db.collection.initializeUnorderedBulkOp(); 
    }
})
// Clean up remaining operations in queue
if (counter % 1000 !== 0) { bulk.execute(); }

下一个示例适用于新的 MongoDB 版本 3.2,它从 deprecated 开始使用 Bulk API,并使用 bulkWrite() 提供了一组更新的 api。

它使用与上面相同的游标,但使用相同的 forEach() 游标方法创建具有批量操作的数组,以将每个批量写入文档推送到数组。因为写入命令可以接受不超过 1000 个操作,所以您需要将操作分组为最多 1000 个操作,并在循环达到 1000 次迭代时重新初始化数组:

var cursor = db.collection.find({ 
        "translation": { 
            "$exists": true, 
            "$not": { "$type": 4 } 
        } 
    }).snapshot(),
    bulkUpdateOps = [];

cursor.forEach(function(doc){ 
    var localization = Object.keys(doc.translation)
        .map(function (key){
            var obj = doc["translation"][key];
            obj["lang"] = key;
            return obj;
        });
    bulkUpdateOps.push({ 
        "updateOne": {
            "filter": { "_id": doc._id },
            "update": { "$set": { "translation": localization } }
         }
    });

    if (bulkUpdateOps.length === 1000) {
        db.collection.bulkWrite(bulkUpdateOps);
        bulkUpdateOps = [];
    }
});         

if (bulkUpdateOps.length > 0) { db.collection.bulkWrite(bulkUpdateOps); }

【讨论】:

  • 感谢您的详细回答,只是想确认它是唯一的方法或最好的方法来模态动态文档
  • 我在光标上添加了.snapshot() 并替换了邪恶的相等运算符。我希望你不介意。;)
  • @chridam 我假设这样的索引正确吗?db.collection.createIndex({'translation.name': 'text','translation.description':'text'}
  • @AbdulHameed 感谢您的更正。据我所知,是的,我相信这是索引字段的唯一方法,因为它们涉及到动态键。
【解决方案2】:

要在名称字段上创建索引,请像这样使用它db.collectionname.createIndex({"name": 'text'})

为确保创建索引列出使用此命令创建的所有索引

db.collectionname.getIndexes()


编辑

不是关于索引创建方法的问题,问题是如何在所有语言的上述模型中实现

我现在知道了,您无法使用现有文档架构为所有语言编制索引,请更改架构,以下是您可以实现它的一种方法

 {
 "_id" : 1,
 "translation" : [
         {       "language": "en",
                 "name" : "brown fox",
                 "description" : "the quick brown fox jumps over a lazy dog"
         },
         {       "language" : "it",
                 "name" : "brown fox ",
                 "description" : " the quick brown fox jumps over a lazy dog"
         },
         {       "language" :"fr",
                 "name" : "renard brun ",
                 "description" : " le renard brun rapide saute par-dessus un chien paresseux"
         },
         {       "language" : "de",
                 "name" : "brown fox ",
                 "description" : " the quick brown fox jumps over a lazy dog"
         },
         {       "language":"es",
                 "name" : "brown fox ",
                 "description" : " el rápido zorro marrón salta sobre un perro perezoso"
         }
 ]}

然后创建索引为db.collectionname.createIndex({"language" : "text"});

上述假设基于您建议的模型,因为名称和描述是翻译中的关键,而不是顶级对象。不是吗?

不,使用我提供的架构,在名称和描述字段上添加文本索引更容易,并且您可以根据语言进行搜索。

【讨论】:

  • 我已经提到了文档,问题不是关于索引创建方法的问题,问题是如何在所有语言的上述模型中实现
  • 我认为这样的索引正确吗?db.collection.createIndex({'translation.name': 'text','translation.description':'text'}
  • @AbdulHameed - 您可以拥有诸如 translation.name 和 translation.description 之类的索引,但它不会帮助您实现基于语言的搜索。正如我所展示的,请重新构建您的架构。 chridham 提供的答案也显示了相同的方法。
  • 上述假设基于您建议的模型,因为名称和描述是翻译中的关键,而不是顶级对象。不是吗?
  • 不,使用我提供的架构,在 namedescription 字段上拥有文本索引更容易,您可以根据语言进行搜索。
猜你喜欢
  • 1970-01-01
  • 2011-09-06
  • 1970-01-01
  • 2021-06-03
  • 2017-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多