我有这个相对较大(近130000个文件)的MongoDB名称集合,其中包含大量重复的OCR噪音,我尝试使用近似字符串匹配将这些副本组合在一起。
我已经使用Simmetrics library在Java中实现了这一点,如下所示:
DBCursor persons = coll.find(query).addOption(Bytes.QUERYOPTION_NOTIMEOUT);
try{
while(persons.hasNext()){
DBObject p = persons.next();
DBObject personName = (DBObject) p.get("person");
String n1 = personName.get("Name").toString();
System.out.println("\n"+ personName + ":");
DBCursor aliases = coll.find(query).addOption(Bytes.QUERYOPTION_NOTIMEOUT);
try{
while(aliases.hasNext()){
DBObject a = aliases.next();
DBObject aliasName = (DBObject) a.get("person");
String n2 = aliasName.get("Name").toString();
float simLev = new Levenshtein().getSimilarity(n1, n2);
if (simLev >= 0.65){
System.out.println(" "+ aliasName + ", Sim: " + simLev);
}
}
} finally{
aliases.close();
}
}
} finally{
persons.close();
}
因此,我使用两个游标将每个文档与每个文档进行比较,并且(仅用于测试目的)我只打印出65%或更高相似度的匹配(以Levenshtein距离为例)。
1名称的输出示例:
{ "Name" : "Baldaino, Manene M."}:
{ "Name" : "Baldaino, Manene M."}, Sim: 1.0
{ "Name" : "Baldaino, Marlene C4."}, Sim: 0.8095238
{ "Name" : "Baldaino Marlene M"}, Sim: 0.78947365
{ "Name" : "BaldainD, Marlene M."}, Sim: 0.85
{ "Name" : "Baldaino Madene M."}, Sim: 0.8947368
{ "Name" : "Baidaino, Marlene M"}, Sim: 0.78947365
{ "Name" : "Baldaino, Marlene M. 0C"}, Sim: 0.7826087
{ "Name" : "Baldaino, Marlene M. (0"}, Sim: 0.7826087
{ "Name" : "8aldaino, Marlene M,"}, Sim: 0.8
{ "Name" : "Baldaino Madene"}, Sim: 0.7368421
{ "Name" : "Baldaino, Marlene 00"}, Sim: 0.8
{ "Name" : "Baldaino, Marlene hi."}, Sim: 0.8095238
{ "Name" : "BaWaino, Marlene M."}, Sim: 0.78947365
{ "Name" : "Baldaino, Marlene M. (3i"}, Sim: 0.75
{ "Name" : "Bedainc, Marlene M."}, Sim: 0.7368421
{ "Name" : "Baldaino, Marlene M. cfl"}, Sim: 0.75
这个实现并不是非常有效,但在整个Collection上运行它我认为在我的电脑上至少需要40个小时。
有谁知道如何才能获得更好的表现? 我已经阅读了有关使用ElasticSearch with Mongo Connector的信息,但我不想学习使用新工具。
答案 0 :(得分:0)
我认为可以将此请求结果加载到内存中(您可以使用Go of ram)" name"和" id"它会避免循环中的第二个光标。它会提高性能。
List<NameID> nameIds = new List<NameID>(100000);
DBCursor persons = coll.find(query).addOption(Bytes.QUERYOPTION_NOTIMEOUT);
try{
while(persons.hasNext()){
DBObject p = persons.next();
nameIds.add(new NameId((DBObject) p.get("person"),(DBObject) p.get("ID"))
}
} } finally{
persons.close();
} }
循环算法中的列表。
答案 1 :(得分:0)
有一种非常快速的算法可以对一大组条目进行字符串相似性。检查Simstring [1]。这是高度优化的方式来做余弦,jaccard和骰子字符串的相似之处。 作者声称他可以查询Google Web1T unigrams(13,588,391字符串),每个查询1.10 [ms](在Intel Xeon 5140 2.33 GHz CPU上)的余弦相似度≥0.7。
首先它构建了一个ngrams映射,然后给出一个查询,它计算出它应该匹配的最小ngram匹配集。
我用它来匹配数百万个Freebase名称和一组实体名称以及其他数百万条目。
我最近在Scala上实现了一个实现[2]。但是你也可以使用Chokkan实现(需要从c ++编译,然后为Java生成swig类)。
如果你从mongo转出字符串,并使用这个数据结构,你绝对可以非常快速地计算近似的字符串匹配。
答案 2 :(得分:0)
目前您只查看文档中的person.Name子字段, 但是你正在从数据库加载整个文档 - 浪费RAM和带宽。
这样做:
find(query).projection(new Document("person.Name", 1))
应该加快速度。