快速摘要:
我有一个文档集合,其中每个文档都有一个名称数组;当用户键入名称列表时,我想在文档的名称列表中找到所有用户输入名称的所有文档。点击指数会更好,因为我们使用的当前策略需要几秒钟。
背景
我正在尝试提高针对患者姓名的查询的效果。人名很复杂,给我带来两个大问题:
要解决问题#1,我们将患者姓名拆分并存储为数组。要解决问题#2,我们在拆分之前将名称小写。我们还按字典顺序对数组进行排序(不确定是否需要这样做?)。
所以这些'名字'在我们的文件中都变成了[“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来解决这个问题的规范方法?
答案 0 :(得分:0)
对于使用MongoDB进行索引,您可以考虑使用几种不同的方法。
索引名称和变体的常用方法是基于搜索词数组实现多键搜索(如您所见)。 MongoDB手册中还有一个例子:Model Data to Support Keyword Search。使用此方法,您可以索引多个相关关键字以进行搜索,并控制其他关键字。索引字通常以小写形式存储,具有常见变体,因此您不必使用正则表达式匹配。如果正则表达式区分大小写并且在匹配字符串的开头有一个锚(^),则Regular expression matches只能有效地使用索引。
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进行其他操作,但我不认为在这种情况下这会有所帮助。