2
votes

I am trying to process logs via Spark Streaming and Spark SQL. The main idea is to have a "compacted" dataset with Parquet format for "old" data converted to DataFrame as needed for queries, the compacted dataset loading is done with:

    SQLContext sqlContext = JavaSQLContextSingleton.getInstance(sc.sc());
    DataFrame compact = null;
    compact = sqlContext.parquetFile("hdfs://auto-ha/tmp/data/logs");

As the uncompacted dataset (I compact the dataset daily) is composed of many files, I would like to have the data in the current day within a DStream in order to get those queries fast.

I have tried the DataFrame approach without results....

    DataFrame df = JavaSQLContextSingleton.getInstance(sc.sc()).createDataFrame(lastData, schema);
    df.registerTempTable("lastData");
    JavaDStream SumStream = inputStream.transform(new Function<JavaRDD<Row>, JavaRDD<Object>>() {
        @Override
        public JavaRDD<Object> call(JavaRDD<Row> v1) throws Exception {
            DataFrame df = JavaSQLContextSingleton.getInstance(v1.context()).createDataFrame(v1, schema);
            ......drop old data from lastData table                                
            df.insertInto("lastData");

        }
    });

Using this approach I do not get any results if I query the temp table in a different thread for example.

I have also tried to use the RDD transform method, more specifically I tried to follow the Spark Example where I create a empty RDD and then I union the DSStream RDD contents with the empty RDD:

  JavaRDD<Row> lastData = sc.emptyRDD();
  JavaDStream SumStream = inputStream.transform(new Function<JavaRDD<Row>, JavaRDD<Object>>() {
        @Override
        public JavaRDD<Object> call(JavaRDD<Row> v1) throws Exception {
            lastData.union(v1).filter(let only recent data....);
        }
    });

This approach does not work too as I do not get any contents in the lastData

Could I use for this purpose Windowed computations or updateStateBy key?

Any suggestions?

Thanks for your help!

2

2 Answers

4
votes

Well I finally got it.

I use updateState function and return 0 if the timestamp is older than 24 hour like this.

      final static Function2<List<Long>, Optional<Long>, Optional<Long>> RETAIN_RECENT_DATA
        = (List<Long> values, Optional<Long> state) -> {
            Long newSum = state.or(0L);
            for (Long value : values) {
                newSum += value;
            }
            //current milis uses UTC
            if (System.currentTimeMillis() - newSum > 86400000L) {
                return Optional.absent();
            } else {
                return Optional.of(newSum);
            }
        };

Then on each batch I register the DataFrame as temp table:

finalsum.foreachRDD((JavaRDD<Row> rdd, Time time) -> {
        if (!rdd.isEmpty()) {
            HiveContext sqlContext1 = JavaSQLContextSingleton.getInstance(rdd.context());
            if (sqlContext1.cacheManager().isCached("alarm_recent")) {
                sqlContext1.uncacheTable("alarm_recent");
            }
            DataFrame wordsDataFrame = sqlContext1.createDataFrame(rdd, schema);
            wordsDataFrame.registerTempTable("alarm_recent");

            wordsDataFrame.cache();//    
            wordsDataFrame.first();
        }
        return null;
    });
1
votes

You could use mapwithState with Spark1.6. The mapwithState function is much more efficient and easy to implement.

Take a look at this link.

mapwithState supports cool functionality like State time out and initialRDD which comes handy while maintaining a Stateful Dstream.

Thanks Manas