Существует много подходов; это то, что может делать вещи параллельно:
import org.apache.spark.sql.functions._
import sqlContext.implicits._
val origDF = sc.parallelize(Seq(
("1", "a", "b"),
("2", "c", "d"),
("3", "e", "f")
)).toDF("k", "v1", "v2")
val newDF = sc.parallelize(Seq(
("1", "a", "b"),
("2", "c2", "d"),
("4", "g", "h")
)).toDF("k", "v1", "v2")
val df1 = origDF.except(newDF) // if k not exists in df2, then deleted
//df1.show(false)
val df2 = newDF.except(origDF) // if k not exists in df1, then added
//df2.show(false)
// if no occurrence in both dfs, then the same
// if k exists in both, then k in df2 = modified
df1.createOrReplaceTempView("df1")
df2.createOrReplaceTempView("df2")
val df3 = spark.sql("""SELECT df1.k, df1.v1, df1.v2, "deleted" as operation
FROM df1
WHERE NOT EXISTS (SELECT df2.k
FROM df2
WHERE df2.k = df1.k)
UNION
SELECT df2.k, df2.v1, df2.v2, "added" as operation
FROM df2
WHERE NOT EXISTS (SELECT df1.k
FROM df1
WHERE df1.k = df2.k)
UNION
SELECT df2.k, df2.v1, df2.v2, "modified" as operation
FROM df2
WHERE EXISTS (SELECT df1.k
FROM df1
WHERE df1.k = df2.k)
""")
df3.show(false)
возвращает:
+---+---+---+---------+
|k |v1 |v2 |operation|
+---+---+---+---------+
|4 |g |h |added |
|2 |c2 |d |modified |
|3 |e |f |deleted |
+---+---+---+---------+
Не так сложно, нет стандартной утилиты.
Часто невозможно сказать, что «правильно» или «неправильно», когда речь идет о дизайне классов. По этой теме есть много руководств, шаблонов, рекомендаций и т. Д., Но, в конце концов, имхо, это много об опыте прошлых проектов. Мой опыт показывает, что лучше не слишком беспокоиться об этом и постепенно улучшать свой код / структуру небольшими шагами. Поэкспериментируйте и посмотрите, как выглядят / ощущаются некоторые идеи / изменения. И, конечно, всегда полезно учиться у других. прочитать много кода и проанализировать его, попытаться понять :).
Если вы хотите прочитать о теории, я могу порекомендовать Крейга Ларманнса «Применение UML и шаблонов: введение в объектно-ориентированный анализ, дизайн и итеративную разработку» Amazon . Он охватывает несколько частей вашего вопроса, дает некоторые приблизительные рекомендации и показывает их на примере приложения. Книга понравилась.
Не могли бы вы загрузить куда-нибудь свое приложение? Возможно, на github или около того, возможно, вы могли бы попросить несколько конкретных советов.
При разработке классов мы следуем следующим принципам:
Изменить: шаблоны проектирования помогают привести ваш код в соответствие с этими принципами.
Попробуйте сделать каждый метод простым для модульного тестирования. Я считаю, что это всегда способствует большей читабельности / понятности моих проектов. Существует множество правил OOAD - SRP, DRY и т. Д. Постарайтесь помнить об этом при рефакторинге.
Шаблоны проектирования фактически стали стандартом для хорошего проектирования классов. Как правило, каждый шаблон имеет конкретный вариант использования или сценарий, к которому он применяется. Если вы можете идентифицировать это в своем коде, вы можете использовать шаблон для создания чего-то, что имеет больше смысла и обычно имеет меньше зависимостей.
Рефакторинг - это инструмент, который вы использовали бы для выполнения этих радикальных изменений. Хорошая IDE поможет провести рефакторинг.
Я рекомендую книгу Мартина Фаулера «Рефакторинг» за тонны практические примеры итеративного преобразования плохого дизайна в хороший дизайн.