MongoDB:如何存储人名以对多个名称进行索引不区分大小写的查询?

时间:2013-04-01 21:41:32

标签: mongodb

快速摘要:

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

背景

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

  1. 人们有多个名字。或者他们可能没有。并且他们可能会以随机顺序给他们
  2. 人名不区分大小写(至少,我们假设不应该对它们进行查询),mongodb目前不支持case-insensitive indexes
  3. 要解决问题#1,我们将患者姓名拆分并存储为数组。要解决问题#2,我们在拆分之前将名称小写。我们还按字典顺序对数组进行排序(不确定是否需要这样做?)。

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

    • “UID ^ DUPE”
    • “UID,DUPE”
    • “UID DUPE”
    • “DUPE 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/
            ]
        ]
    }
    }
    

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

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

    我的实际问题:

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

2 个答案:

答案 0 :(得分:0)

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

多键索引

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

MongoDB 2.4文本搜索

MongoDB 2.4引入了一个新的text search feature,它也可以帮助你的用例。此功能仍被视为2.4版本的“测试版”,必须为explicitly enabled text 索引不区分大小写,搜索结果按排名顺序返回。如果在文本索引中包含多个字段(例如,“last_name”和“first_name”),则还可以设置field weights以用于计算相关性。值得注意的是,文本搜索功能包括language-based stemming,它有助于正常搜索的相关性(多个单词可以共享一个共同的根目录),但可能不会对匹配患者姓名(您可能需要如果输入的名称不正确,则模糊匹配。)

患者姓名的模糊匹配

对于名称匹配,有几个常见的phonetic algorithms用于实现“听起来像”匹配。根据文化差异,例如拼写,发音和你的名字语料库中使用的语言,它们的效果各不相同。

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

建议的方法

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

答案 1 :(得分:0)

这看起来像是一种合理的方法。您可能尝试的另一种方法是在文档中存储所有排列,以便您可以避免$and操作。您也许可以存储初始加姓氏变体,允许精确匹配而不是start-with regex。

有些记录会有很多排列,但大多数情况下,我认为只有两个名字和几个排列,例如。

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

这种方法也可能允许您存储一些常见的替代方案,例如凯瑟琳,猫,凯特。或者你可以通过将所有替代方案映射到一些规范形式来处理它。

您可以使用RegEx搜索find partial matches进行其他操作,但我不认为在这种情况下这会有所帮助。