Почему использование кэша в потоковых наборах данных не удается с помощью " AnalysisException: запросы с потоковыми источниками должны выполняться с помощью writeStream.start()"?

SparkSession
  .builder
  .master("local[*]")
  .config("spark.sql.warehouse.dir", "C:/tmp/spark")
  .config("spark.sql.streaming.checkpointLocation", "C:/tmp/spark/spark-checkpoint")
  .appName("my-test")
  .getOrCreate
  .readStream
  .schema(schema)
  .json("src/test/data")
  .cache
  .writeStream
  .start
  .awaitTermination

при выполнении этого образца в spark 2.1.0 я получил ошибку. Без .cache опция работала по назначению, но с Я:

исключение в потоке" main " org.апаш.искра.язык SQL.AnalysisException: запросы с потоковыми источниками должны выполняться с помощью writeStream.начать();; FileSource[src / тест / данные] на org.apache.spark.sql.catalyst.analysis.UnsupportedOperationChecker$.org$apache$spark$sql$catalyst$analysis$UnsupportedOperationChecker$$throwError(UnsupportedOperationChecker.scala:196) в орг.апаш.искра.язык SQL.катализатор.анализ.UnsupportedOperationChecker$$anonfun$checkForBatch$1.применить(UnsupportedOperationChecker.scala: 35) в орг.апаш.искра.язык SQL.катализатор.анализ.UnsupportedOperationChecker$$anonfun$checkForBatch$1.применить(UnsupportedOperationChecker.scala: 33) на орг.апаш.искра.язык SQL.катализатор.деревья.объект TreeNode.foreachUp(узлов дерева.scala: 128) в орг.апаш.искра.язык SQL.катализатор.анализ.UnsupportedOperationChecker$.checkForBatch (UnsupportedOperationChecker.scala: 33) в орг.апаш.искра.язык SQL.исполнение.QueryExecution.assertSupported (QueryExecution.scala: 58) в орг.апаш.искра.язык SQL.исполнение.QueryExecution.withCachedData$lzycompute (QueryExecution.scala: 69) на орг.апаш.искра.язык SQL.исполнение.QueryExecution.withCachedData (QueryExecution.scala: 67) в орг.апаш.искра.язык SQL.исполнение.QueryExecution.optimizedPlan$lzycompute (QueryExecution.scala: 73) в орг.апаш.искра.язык SQL.исполнение.QueryExecution.optimizedPlan (QueryExecution.scala: 73) в орг.апаш.искра.язык SQL.исполнение.QueryExecution.sparkPlan$lzycompute (QueryExecution.scala: 79) в орг.апаш.искра.язык SQL.исполнение.QueryExecution.sparkPlan (QueryExecution.scala: 75) на орг.апаш.искра.язык SQL.исполнение.QueryExecution.executedPlan$lzycompute (QueryExecution.scala: 84) в орг.апаш.искра.язык SQL.исполнение.QueryExecution.executedPlan (QueryExecution.scala: 84) в орг.апаш.искра.язык SQL.исполнение.CacheManager$$anonfun$cacheQuery$1.применить(CacheManager.scala: 102) в орг.апаш.искра.язык SQL.исполнение.CacheManager.writeLock(CacheManager.scala: 65) в орг.апаш.искра.язык SQL.исполнение.CacheManager.cacheQuery (CacheManager.scala: 89) на орг.апаш.искра.язык SQL.Набор данных.сохраняются(набора данных.scala: 2479) в орг.апаш.искра.язык SQL.Набор данных.кэш(набор данных.scala: 2489) в орг.меня.App$.main (App.scala: 23) в орг.меня.App.main (App.scala)

есть идеи?

1 ответов


ваш (очень интересный) случай сводится к следующей строке (которую вы можете выполнить в spark-shell):

scala> :type spark
org.apache.spark.sql.SparkSession

scala> spark.readStream.text("files").cache
org.apache.spark.sql.AnalysisException: Queries with streaming sources must be executed with writeStream.start();;
FileSource[files]
  at org.apache.spark.sql.catalyst.analysis.UnsupportedOperationChecker$.org$apache$spark$sql$catalyst$analysis$UnsupportedOperationChecker$$throwError(UnsupportedOperationChecker.scala:297)
  at org.apache.spark.sql.catalyst.analysis.UnsupportedOperationChecker$$anonfun$checkForBatch.apply(UnsupportedOperationChecker.scala:36)
  at org.apache.spark.sql.catalyst.analysis.UnsupportedOperationChecker$$anonfun$checkForBatch.apply(UnsupportedOperationChecker.scala:34)
  at org.apache.spark.sql.catalyst.trees.TreeNode.foreachUp(TreeNode.scala:127)
  at org.apache.spark.sql.catalyst.analysis.UnsupportedOperationChecker$.checkForBatch(UnsupportedOperationChecker.scala:34)
  at org.apache.spark.sql.execution.QueryExecution.assertSupported(QueryExecution.scala:63)
  at org.apache.spark.sql.execution.QueryExecution.withCachedData$lzycompute(QueryExecution.scala:74)
  at org.apache.spark.sql.execution.QueryExecution.withCachedData(QueryExecution.scala:72)
  at org.apache.spark.sql.execution.QueryExecution.optimizedPlan$lzycompute(QueryExecution.scala:78)
  at org.apache.spark.sql.execution.QueryExecution.optimizedPlan(QueryExecution.scala:78)
  at org.apache.spark.sql.execution.QueryExecution.sparkPlan$lzycompute(QueryExecution.scala:84)
  at org.apache.spark.sql.execution.QueryExecution.sparkPlan(QueryExecution.scala:80)
  at org.apache.spark.sql.execution.QueryExecution.executedPlan$lzycompute(QueryExecution.scala:89)
  at org.apache.spark.sql.execution.QueryExecution.executedPlan(QueryExecution.scala:89)
  at org.apache.spark.sql.execution.CacheManager$$anonfun$cacheQuery.apply(CacheManager.scala:104)
  at org.apache.spark.sql.execution.CacheManager.writeLock(CacheManager.scala:68)
  at org.apache.spark.sql.execution.CacheManager.cacheQuery(CacheManager.scala:92)
  at org.apache.spark.sql.Dataset.persist(Dataset.scala:2603)
  at org.apache.spark.sql.Dataset.cache(Dataset.scala:2613)
  ... 48 elided

причина этого оказалась довольно простой в объяснении (нет каламбура для Искры SQL explain предназначен).

spark.readStream.text("files") создает так называемый потоковая передача данных.

scala> val files = spark.readStream.text("files")
files: org.apache.spark.sql.DataFrame = [value: string]

scala> files.isStreaming
res2: Boolean = true

потоковые наборы данных являются основой Spark SQL в Структурированная Потоковая Передача.

как вы, возможно, читали в Structured Трансляции -Пример:

а затем начать потоковое вычисление с помощью start().

цитирование scaladoc из Datastreamwriter's старт:

start (): StreamingQuery запускает выполнение потокового запроса, который будет постоянно выводить результаты на заданный путь по мере поступления новых данных.

Итак, вы должны использовать start (или foreach) чтобы начать выполнение потокового запроса. Ты уже знал это.

но...есть Неподдерживаемые Операции в структурированной потоковой передачи:

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

если вы попробуете любую из этих операций, вы увидите AnalysisException как "операция XYZ не поддерживается потоковыми фреймами данных/наборами данных".

знакомое, не так ли?

cache и не в списке неподдерживаемых операций, но это потому, что он просто был упущен (я сообщил Искра-20927 исправить).

cache должен был быть в списке, как это тут выполнить запрос до получения запроса зарегистрировано в Искра CacheManager в SQL.

давайте углубимся в глубины Spark SQL...задержать дыхание...

cache is persist пока persist запрашивает текущий CacheManager для кэширования запроса:

sparkSession.sharedState.cacheManager.cacheQuery(this)

при кэшировании запроса CacheManager тут выполнить:

sparkSession.sessionState.executePlan(planToCache).executedPlan

что мы знаю не допускается, так как это start (или foreach), чтобы сделать так.

проблема решена!