提取或过滤Spark DataFrame的MapType

时间:2016-04-18 20:23:55

标签: apache-spark dataframe apache-spark-sql

我有一个包含各种列的DataFrame。 一列包含Map [Integer,Integer []]。 它看起来像{ 2345 -> [1,34,2]; 543 -> [12,3,2,5]; 2 -> [3,4]} 现在我需要做的是过滤掉一些键。 我在Java中有一组整数(javaIntSet),我应该使用它来过滤

col(x).keySet.isin(javaIntSet)

即。上面的地图应该只包含密钥2和543而不包含其他两个,并且在过滤后应该看起来像{543 -> [12,3,2,5]; 2 -> [3,4]}

如何使用Java Column Class的文档很稀疏。 如何提取col(x),以便我可以在java中过滤它,然后用过滤后的地图替换单元格数据。或者我正在忽略列的任何有用功能。 我可以写一个UDF2<Map<Integer, Integer[]>,Set<Integer>,Map<Integer,Integer[]> 我可以写一个UDF1<String,String>但我不太确定它如何适用于更复杂的参数。

通常,javaIntSet只有十几个,通常少于100个值。地图通常也只有少数条目(通常为0-5)。

我必须在Java中这样做(不幸的是),但我熟悉Scala。我将自己翻译成Java的Scala答案已经非常有用了。

1 个答案:

答案 0 :(得分:2)

您不需要UDF。可以用一个更干净,但你可以用Article

轻松完成
CategoryId

然后你可以使用explode:

var express = require('express');
var ws = require('nodejs-websocket');
var app = express();
var socket = ws.connect("ws://localhost:5000");

var port = 8000;

app.get('/', function(req, res) {
  var r = JSON.stringify({
    type: "page request",
    request: {
      url: req.query.url,
      app: req.query.app
    }
  });
  socket.on("text", function(str){
    console.log(str);
    var d = JSON.parse(str);
    res.send(d.response.body);
    return;
  });
  socket.sendText(r);
});

app.listen(port, function(){
  console.log("Node app is running on port", port);
});

如果您确实想要DataFrame.explode,它将如下所示:

case class MapTest(id: Int, map: Map[Int,Int])
val mapDf = Seq(
  MapTest(1, Map((1,3),(2,10),(3,2)) ),
  MapTest(2, Map((1,12),(2,333),(3,543)) )
).toDF("id", "map")

mapDf.show
+---+--------------------+
| id|                 map|
+---+--------------------+
|  1|Map(1 -> 3, 2 -> ...|
|  2|Map(1 -> 12, 2 ->...|
+---+--------------------+

mapDf.explode($"map"){ case Row(map: Map[Int,Int] @unchecked) => { val newMap = map.filter(m => m._1 != 1) // <-- do filtering here Seq(Tuple1(newMap)) } }.show +---+--------------------+--------------------+ | id| map| _1| +---+--------------------+--------------------+ | 1|Map(1 -> 3, 2 -> ...|Map(2 -> 10, 3 -> 2)| | 2|Map(1 -> 12, 2 ->...|Map(2 -> 333, 3 -...| +---+--------------------+--------------------+ 稍微复杂一点,但最终更灵活。例如,您可以将原始行划分为两行 - 一行包含已过滤掉元素的地图,另一行包含反向的地图 - 已过滤的元素。