Как сделать самодекартово произведение по разным разделам набора данных Spark?

Мне нужно сравнить разные строки набора данных два к двум. В идеале я бы сделал самодекартово произведение набора данных, затем удалил бы повторяющиеся сравнения (поскольку A, B совпадает с B, A) и, наконец, я бы сделал map, чтобы решить, равны ли каждая пара строк или нет. Однако это приведет к огромному количеству строк, и я не могу позволить себе вычислительные затраты, которые это повлечет.

Чтобы максимально сократить результирующее количество строк, я хотел бы отсортировать строки и применить самодекартово произведение только к разным подмножествам всего набора данных. Например, подмножества будут следующими:

  • От строки 0 до 100
  • С 50 по 150 ряд
  • С 100 по 200 ряд
  • ....

Таким образом, я бы сравнил каждую строку с ее соседями, и конечное количество сравниваемых строк было бы намного меньше, чем если бы я выполнял самодекартово произведение по всему набору данных.

Моя попытка

На самом деле я реализовал решение, но по какой-то причине это занимает много времени, даже если набор данных небольшой.

Во-первых, я сортирую и архивирую набор данных, чтобы идентифицировать каждый столбец.

val sortedByTitle = journalArticles.orderBy("title")
val withIndex = sortedByTitle.rdd.zipWithIndex().toDF("article", "index").as[IndexArticle]

Затем я сделал функцию для деления и самодекартова произведения:

def divideAndCartesian(data: Dataset[IndexArticle], fromIndex: Long, divisionSize: Int): Dataset[CartessianIndexArticles] = {
  val division = data.filter(x => x.index >= fromIndex && x.index < fromIndex + divisionSize)
  if(division.count() == 0) Seq.empty[(JournalArticle, Long, JournalArticle, Long)].toDF("article1", "index1", "article2", "index2").as[CartessianIndexArticles]
  else
    division.crossJoin(division).toDF("article1", "index1", "article2", "index2").as[CartessianIndexArticles].union(divideAndCartesian(data, fromIndex + (divisionSize / 2), divisionSize))
}

Любые идеи?

Благодарю вас!


person bergacat1    schedule 07.04.2017    source источник
comment
В моем ответе ниже я бы сделал карту, чтобы решить, равны ли каждая пара строк или нет. Я предположил, что вы не стремились отфильтровать точные дубликаты, не так ли?   -  person Pascal Soucy    schedule 07.04.2017
comment
или вы можете groupby() ->agg()-›where()   -  person Ramandeep Nanda    schedule 08.04.2017
comment
@PascalSucy нет, я не ищу точных дубликатов. Я прочитаю о том, что вы предлагаете.   -  person bergacat1    schedule 08.04.2017


Ответы (1)


Я предлагаю вам прочитать о Approximate Similarity Join использовании хеширования с учетом местоположения. Согласно документации:

Общая идея LSH состоит в том, чтобы использовать семейство функций («семейства LSH») для хэширования точек данных в корзины так, чтобы точки данных, которые близки друг к другу, с высокой вероятностью находились в одних и тех же корзинах, а точки данных, которые далеко друг от друга, скорее всего, в разных ведрах.

В частности, приблизительное соединение подобия:

Приближенное соединение по сходству берет два набора данных и приблизительно возвращает пары строк в наборах данных, расстояние между которыми меньше заданного пользователем порога. Соединение по приблизительному сходству поддерживает как объединение двух разных наборов данных, так и самосоединение. Самосоединение создаст несколько повторяющихся пар.

Короче говоря, LSH разделит ваши строки на группы, чтобы избежать сравнения всех возможных пар. Например, после того, как вы выполните соединение по приблизительному сходству, если вы используете Случайная проекция с сегментами для евклидова расстояния

val joined = model.approxSimilarityJoin(data, data, 2.5)

Все пары в joined, которые находятся в пределах 2,5 расстояния, будут возвращены. Затем вам решать, достаточно ли это приближение для фильтрации дубликатов, или вы хотите вычислить точное сходство между строками.

person Pascal Soucy    schedule 07.04.2017