1

快速总结:

我有一个文档集合,其中每个文档都有一个名称数组;当用户输入姓名列表时,我想在文档的姓名列表中查找所有用户输入姓名的所有文档。命中索引会更好,因为我们当前使用的策略需要几秒钟。

背景:

我正在尝试提高我们对患者姓名的查询的性能。人名很复杂,给我带来了两个大问题:

  1. 人们有多个名字。或者也许他们没有。他们可能会以随机顺序给他们
  2. 人名不区分大小写(至少,我们假设对他们的查询不应该是),并且 mongodb 目前不支持不区分大小写的索引

为了解决问题 #1,我们将患者姓名拆分并将其存储为数组。为了解决问题 #2,我们在拆分之前将名称小写。我们还按字典顺序对数组进行排序(不确定这是否需要?)。

所以这些“名字”在我们的文档中都变成了 ["dupe", "uid"]:

  • “UID^DUPE”
  • “UID,骗子”
  • “UID 欺骗”
  • “欺骗 UID”

然后,我们可以进行一个将命中索引的查询:

db.mycollection.find({"data.crunchedName":/^dup/}, {_id:0, "data.crunchedName":1}).explain()

根据 explain() 命中索引:

{
"cursor" : "BtreeCursor data.crunchedName_ multi",
"nscanned" : 13,
"nscannedObjects" : 12,
"n" : 12,
"millis" : 0,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : true,
"indexOnly" : false,
"indexBounds" : {
    "data.crunchedName" : [
        [
            "dup",
            "duq"
        ],
        [
            /^dup/,
            /^dup/
        ]
    ]
}
}

尽管无论出于何种原因,我都无法将其显示为“仅索引”。我认为这在实践中并不重要。

如果我尝试使用 $and 绑定多个名称,则只有第一个名称会命中索引。因此,根据名称的顺序,存在潜在的性能差异。我认为这一定是因为没有办法在列表中的成对事物上指定索引。我不确定您是否愿意这样做,因为索引会很大。

我的实际问题:

这是一个体面的方法吗?如果用户决定键入“S Alexander”之类的内容,是否还有其他选项不会出现性能问题?有没有一些我找不到的使用 mongo 解决这个问题的规范方法?

4

2 回答 2

0

就使用 MongoDB 进行索引而言,您可以考虑几种不同的方法。

多键索引

索引名称和变体的一种常用方法是实现基于搜索词数组的多键搜索(正如您所做的那样)。MongoDB 手册中也有一个例子:Model Data to Support Keyword Search。使用这种方法,您可以索引多个相关关键字以进行搜索,并控制其他关键字。索引词通常以小写形式存储,具有常见的变体,因此您不必使用正则表达式匹配。 只有当正则表达式区分大小写并且在匹配字符串的开头有一个锚 (^) 时,正则表达式匹配才能有效地使用索引。

MongoDB 2.4 文本搜索

MongoDB 2.4 引入了一个新的文本搜索功能,它也可以帮助您的用例。对于 2.4 版本,此功能仍被视为“测试版”,必须明确启用文本索引不区分大小写,搜索结果按排名顺序返回。如果您在文本索引中包含多个字段(例如,“last_name”和“first_name”),您还可以设置字段权重以用于计算相关性。值得注意的是,文本搜索功能包括基于语言的词干提取这有助于正常搜索的相关性(其中多个单词可以共享一个共同的词根),但对于匹配患者姓名可能没有那么有用(如果名称输入不正确,您可能需要更模糊的匹配)。

患者姓名的模糊匹配

对于名称匹配,有几种常见的语音算法来实现“听起来像”匹配。这些具有不同的效果,具体取决于文化差异,例如拼写、发音和名称语料库中使用的语言。

一篇很好的概述文章是Using Fuzzy Matching to Search by Sound with Python,其中包括:

建议的方法

我认为您最好的方法是将多键索引与语音算法结合使用。

于 2013-05-02T05:06:55.083 回答
0

这看起来是一种合理的方法。您可能会尝试的一种替代方法是将所有排列存储在文档中,这样您就可以避免该$and操作。您也许还可以存储允许精确匹配而不是以正则表达式开头的初始加姓氏变体。

有些记录会有很多排列,但我认为大多数记录只有两个名称和很少的排列,例如

["John Smith", "Smith John", "J Smith", "John S"]

这种方法还可能允许您存储一些常见的替代品,例如 Catherine、Cat、Kate。或者,您可以通过将所有备选方案映射到某些规范形式来处理这个问题。

您可以使用 RegEx 搜索执行其他技巧来查找部分匹配项,但我认为这在这种情况下无济于事。

于 2013-05-02T05:29:50.533 回答