Вычисление косинусного сходства путем преобразования текста в вектор с использованием tf-idf

Я новичок в Apache Spark, хочу найти похожий текст из кучи текста, пробовал себя следующим образом:

У меня 2 РДД-

1-й СДР содержит неполный текст следующим образом:

[0,541 Suite 204, Redwood City, CA 94063]
[1,6649 N Blue Gum St, New Orleans,LA, 70116]
[2,#69, Los Angeles, Los Angeles, CA, 90034]
[3,98 Connecticut Ave Nw, Chagrin Falls]
[4,56 E Morehead Webb, TX, 78045]

2-й СДР содержит правильный адрес следующим образом:

[0,541 Jefferson Avenue, Suite 204, Redwood City, CA 94063]
[1,6649 N Blue Gum St, New Orleans, Orleans, LA, 70116]
[2,25 E 75th St #69, Los Angeles, Los Angeles, CA, 90034]
[3,98 Connecticut Ave Nw, Chagrin Falls, Geauga, OH, 44023]
[4,56 E Morehead St, Laredo, Webb, TX, 78045]

Написал этот код, это занимает много времени, может ли кто-нибудь сказать мне, как правильно это сделать в Apache Spark с использованием scala.

val incorrect_address_count = incorrect_address_rdd.count()
val all_address = incorrect_address_rdd.union(correct_address_rdd) map (_._2.split(" ").toSeq)

val hashingTF = new HashingTF()
val tf = hashingTF.transform(all_address)
.zipWithIndex()

val input_vector_rdd = tf.filter(_._2 < incorrect_address_count)

val address_db_vector_rdd = tf.filter(_._2 >= incorrect_address_countt)
.map(f => (f._2 - input_count, f._1))
.join(correct_address_rdd)
.map(f => (f._2._1, f._2._2))

val input_similarity_rdd = input_vector_rdd.cartesian(address_db_vector_rdd)
.map(f => {

val cosine_similarity = cosineSimilarity(f._1._1.toDense, f._2._1.toDense)

(f._1._2, cosine_similarity, f._2._2)
})


def cosineSimilarity(vectorA: Vector, vectorB: Vector) = {

var dotProduct = 0.0
var normA = 0.0
var normB = 0.0
var index = vectorA.size - 1

for (i <- 0 to index) {
dotProduct += vectorA(i) * vectorB(i)
normA += Math.pow(vectorA(i), 2)
normB += Math.pow(vectorB(i), 2)
}
(dotProduct / (Math.sqrt(normA) * Math.sqrt(normB)))
}

person Kshitij Kulshrestha    schedule 18.09.2015    source источник


Ответы (1)


У меня была почти такая же проблема. У меня было 370 тыс. строк и 2 вектора по 300 тыс. и 400 тыс. для каждой строки. Я умножаю тестовые строки rdd на оба этих вектора.

Есть 2 больших улучшения, которые вы можете сделать. Один – предварительно рассчитать нормы. Они не меняются. Во-вторых, использовать разреженный вектор. Вы используете vector.size, это 300 КБ, если вы делаете это так. Если вы используете Sparse, он повторяется для каждого ключевого слова (20-30 в строке).

Кроме того, я боюсь, что это наиболее эффективный способ, потому что вычисления не нужно перемешивать. Если у вас есть хорошая оценка в конце, вы можете фильтровать по баллам, и все будет быстро. (Я имею в виду, какой балл вам достаточно.)

def cosineSimilarity(vectorA: SparseVector, vectorB:SparseVector,normASqrt:Double,normBSqrt:Double) :(Double,Double) = {
  var dotProduct = 0.0
  for (i <-  vectorA.indices){ 
    dotProduct += vectorA(i) * vectorB(i)
  }
  val div = (normASqrt * normBSqrt)
  if( div == 0 )
    (dotProduct,0)
  else
    (dotProduct,dotProduct / div)
}
person mcelikkaya    schedule 15.09.2017