Apache spark 如何使用Spark查找10亿条记录的最近邻?
鉴于10亿条记录包含以下信息:Apache spark 如何使用Spark查找10亿条记录的最近邻?,apache-spark,pyspark,spark-dataframe,nearest-neighbor,euclidean-distance,Apache Spark,Pyspark,Spark Dataframe,Nearest Neighbor,Euclidean Distance,鉴于10亿条记录包含以下信息: ID x1 x2 x3 ... x100 1 0.1 0.12 1.3 ... -2.00 2 -1 1.2 2 ... 3 ... 对于上面的每个ID,我想根据向量的欧几里德距离(x1,x2,…,x100)找到前10个最接近的ID 计算这个问题的最佳方法是什么?您没有提供太多细节,但我解决这个问题的一般方法是: 将记录转换为数据结构,如以(ID,x1..x100)为标签和特征的 映射每个记录,
ID x1 x2 x3 ... x100
1 0.1 0.12 1.3 ... -2.00
2 -1 1.2 2 ... 3
...
对于上面的每个ID,我想根据向量的欧几里德距离(x1,x2,…,x100)找到前10个最接近的ID
计算这个问题的最佳方法是什么?您没有提供太多细节,但我解决这个问题的一般方法是:
{id\u pair:[1,5],distance:123}
# 1. vectorize the features
def vectorize_raw_data(record)
arr_of_features = record[1..99]
LabeledPoint( record[0] , arr_of_features)
# 2,3 + 4 map over each record for comparison
broadcast_var = []
def calc_distance(record, comparison)
# here you want to keep a broadcast variable with a list or dictionary of
# already compared IDs and break if the key pair already exists
# then, calc the euclidean distance by mapping over the features of
# the record and subtracting the values then squaring the result, keeping
# a running sum of those squares and square rooting that sum
return {"id_pair" : [1,5], "distance" : 123}
for record in allRecords:
for comparison in allRecords:
broadcast_var.append( calc_distance(record, comparison) )
# 5. map for 10 closest neighbors
def closest_neighbors(record, n=10)
broadcast_var.filter(x => x.id_pair.include?(record.id) ).takeOrdered(n, distance)
伪代码很糟糕,但我认为它传达了意图。当您将所有记录与所有其他记录进行比较时,这里将有大量的洗牌和排序。总之,您希望将密钥对/距离存储在一个中心位置(就像一个广播变量,虽然这很危险,但会被更新),以减少您执行的欧几里德距离计算总量。对所有记录与所有记录进行蛮力比较是一场失败的战斗。我的建议是使用k-最近邻算法的现成实现,如
scikit learn
提供的算法,然后广播结果的索引和距离数组,然后再进一步
这种情况下的步骤是:
1-按照Bryce的建议对功能进行矢量化,并让您的矢量化方法返回一个浮动列表(或numpy数组),其中包含与功能相同数量的元素
2-将您的scikit learn nn与您的数据相匹配:
nbrs = NearestNeighbors(n_neighbors=10, algorithm='auto').fit(vectorized_data)
3-在矢量化数据上运行经过训练的算法(在您的案例中,训练和查询数据是相同的)
步骤2和3将在pyspark节点上运行,在这种情况下不可并行化。此节点上需要有足够的内存。在我这个拥有150万条记录和4项功能的例子中,花了一两秒钟
在我们为spark实现NN之前,我想我们必须坚持这些变通方法。如果你想尝试一些新的东西,那么就选择它,我有一个解决方案,包括将sklearn与Spark结合起来: 其要点是:
- 集中使用sklearn的k-NN fit()方法
- 然后分布式地使用sklearn的k-NN kneighbors()方法
distances, indices = nbrs.kneighbors(qpa)