数据集 Node.js 中的最近邻
Posted
技术标签:
【中文标题】数据集 Node.js 中的最近邻【英文标题】:nearest neighbour in dataset Node.js 【发布时间】:2012-12-28 22:41:24 【问题描述】:我有一个将数据保存到 MongoDB 的 Node.js 应用程序。 给定一个文档,我想在数据库中找到最相似的文档。
我的想法是实现某种最近邻算法,将所有记录作为训练序列并返回最相似的文档(包括关于这两个文档的相似程度的某种百分比。)
例如在我的数据库中有这些记录...
name: "Bill", age: 10, pc: "Mac", ip: "68.23.13.8"
name: "Alice", age: 22, pc: "Windows", ip: "193.186.11.3"
name: "Bob", age: 12, pc: "Windows", ip: "56.89.22.1"
...我想找到最接近这个的文档
name: "Tom", age: 10, pc: "Mac", ip: "68.23.13.10"
// algorithm returns "Bill", .76
是否有任何 Node 模块/实现采用任何类型的对象/参数并返回其最近的邻居?
【问题讨论】:
你有多少条记录?它们经常更新吗? 我希望有很多 (>5000) 条记录。保存后,它们不会更新,但新记录可能随时到达。 这不是通常作为独立模块实现的东西。这更像是一个算法的事情。更多的是一种艺术。每个人都有不同的需求。解决方案往往是高度定制的。通常,人们使用框架(和大量知识)来构建他们的解决方案。可能最简单的方法是(如果您有资源)使用 Solr 来索引您的数据。然后使用 MoreLikeThis 组件查询:wiki.apache.org/solr/MoreLikeThis 在概念层面上,这个问题有两个因素。一个相似度函数,它接受 2 个文档并返回一个表示它们相似程度的数字。以及重新索引整个集合的频率和数量的策略(提示,每次添加新文档时比较所有对可能不切实际,这是二次时间!) 【参考方案1】:这样做的一个直接方法是计算两个文档之间的差异,差异越大,距离越大。您可以使用最大可能的差异对差异进行归一化,这应该为您提供可以相互比较的相对距离。
看看这个问题,计算 json 文档的差异。
Delta encoding for JSON objects
【讨论】:
如果 ip 仅从 68.23.13.8 更改为 68.23.13.10(即属性的非常小的变化),这是否也会考虑在内?你手头有代码吗? 这将完全取决于差异算法。我发布的问题中的大多数算法只是检查任何字符串更改,而不是区分单个字符串。【参考方案2】:这是一些示例代码。它假定您可以对每个请求运行搜索。如果要修改它,请确保所有相似度函数都返回一个介于 0 和 1 之间的数字。
function tokenize(string)
var tokens = [];
for (var i = 0; i < string.length-1; i++)
tokens.push(string.substr(i,2));
return tokens.sort();
function intersect(a, b)
var ai=0, bi=0;
var result = new Array();
while( ai < a.length && bi < b.length )
if (a[ai] < b[bi] ) ai++;
else if (a[ai] > b[bi] ) bi++;
else /* they're equal */
result.push(a[ai]);
ai++;
bi++;
return result;
function sum(items)
var sum = 0;
for (var i = 0; i < items.length; i++)
sum += items[i];
return sum;
function wordSimilarity(a, b)
var left = tokenize(a);
var right = tokenize(b);
var middle = intersect(left, right);
return (2*middle.length) / (left.length + right.length);
function ipSimilarity(a, b)
var left = a.split('.');
var right = b.split('.');
var diffs = [];
for (var i = 0; i < 4; i++)
var diff1 = 255-left[i];
var diff2 = 255-right[i];
var diff = Math.abs(diff2-diff1);
diffs[i] = diff;
var distance = sum(diffs)/(255*4);
return 1 - distance;
function ageSimilarity(a, b)
var maxAge = 100;
var diff1 = maxAge-a;
var diff2 = maxAge-b;
var diff = Math.abs(diff2-diff1);
var distance = diff / maxAge;
return 1-distance;
function recordSimilarity(a, b)
var fields = [
name:'name', measure:wordSimilarity,
name:'age', measure:ageSimilarity,
name:'pc', measure:wordSimilarity,
name:'ip', measure:ipSimilarity
];
var sum = 0;
for (var i = 0; i < fields.length; i++)
var field = fields[i];
var name = field.name;
var measure = field.measure;
var sim = measure(a[name], b[name]);
sum += sim;
return sum / fields.length;
function findMostSimilar(items, query)
var maxSim = 0;
var result = null;
for (var i = 0; i < items.length; i++)
var item = items[i];
var sim = recordSimilarity(item, query);
if (sim > maxSim)
maxSim = sim;
result = item;
return result
var items = [
name: "Bill", age: 10, pc: "Mac", ip: "68.23.13.8" ,
name: "Alice", age: 22, pc: "Windows", ip: "193.186.11.3" ,
name: "Bob", age: 12, pc: "Windows", ip: "56.89.22.1"
];
var query = name: "Tom", age: 10, pc: "Mac", ip: "68.23.13.10" ;
var result = findMostSimilar(items, query);
console.log(result);
【讨论】:
这就像一个魅力。但是我在ipSimilarity()
上遇到了 TypeError。我通过重命名sum()
方法解决了这个问题。谢谢。以上是关于数据集 Node.js 中的最近邻的主要内容,如果未能解决你的问题,请参考以下文章