Spark中将Vector向量,转为Array数组,存储为txt文件

Spark中,有两种方法可以将数据存为txt文件,一种是基于RDD存储,另一种是使用Spark SQL的Dataset数据结构。

两种存储方法对比:

比较项基于RDD基于Dataset
是否可追加
存储列数不限制只能一列

总的来说,就是基于RDD存储txt文件的话,无法对目录文件进行追加及覆盖写操作,但是可以直接存储多列,而基于Dataset存储的时候,是可以按照SaveMode进行各种选择方式的,但是只能存储一列。

解决办法就是想办法将Dataset中的多列数据合并为一列数据。

 

基于RDD的:

/**
 * 转为RDD存储为TXT文件时,无法进行覆盖和追加
 * 数据为Dataset<Row>
*/

dataset.coalesce(1).toJavaRDD().map((Function<Row, String>) row -> row.toString())
                .map((Function<String, String>) line -> line.replace(",", "|"))
                .saveAsTextFile("/data/example.txt");

基于Dataset操作的时候:

第一步:使用SparkSQL的UDF函数,将Vector向量转为double类型的Array数组

第二步:将所有的列合并为一列,并制定分割符,然后按需求存储数据

Step1:创建示例Dataset

/**
         * 准备数据
         */
        List<Row> data = Arrays.asList(
                RowFactory.create("vector1", Vectors.dense(0.2564752136, -2.154645158, 0.2648491548)),
                RowFactory.create("vector2", Vectors.dense(1.2564213055, -6.158132184, -2.448131585)),
                RowFactory.create("vector3", Vectors.dense(-5.184321865, 5.1481355498, 8.5481513218))
        );
        StructType schema = createStructType(new StructField[]{
                createStructField("vectorId", DataTypes.StringType, false),
                createStructField("vector", new VectorUDT(), false)
        });
        Dataset<Row> dataset = sparkSession.createDataFrame(data, schema);

打印数据格式可以看到

dataset.printSchema();
root
 |-- vectorId: string (nullable = false)
 |-- vector: vector (nullable = false)


dataset.show(false);
+--------+----------------------------------------+
|vectorId|vector                                  |
+--------+----------------------------------------+
|vector1 |[0.2564752136,-2.154645158,0.2648491548]|
|vector2 |[1.2564213055,-6.158132184,-2.448131585]|
|vector3 |[-5.184321865,5.1481355498,8.5481513218]|
+--------+----------------------------------------+

Step2:使用用户自定义函数UDF,将Vector向量转为Array

UserDefinedFunction vector2Array = udf((UDF1<Vector, double[]>) vector -> vector.toArray(), DataTypes.createArrayType(DataTypes.DoubleType));

Dataset<Row> arrayData = dataset.withColumn("vec2array", vector2Array.apply(dataset.col("vector")))
                .select("vectorId", new String[]{"vec2array"});

打印数据格式可以看到

arrayData.printSchema();
root
 |-- vectorId: string (nullable = false)
 |-- vec2array: array (nullable = true)
 |    |-- element: double (containsNull = true)


arrayData.show(false);
+--------+------------------------------------------+
|vectorId|vec2array                                 |
+--------+------------------------------------------+
|vector1 |[0.2564752136, -2.154645158, 0.2648491548]|
|vector2 |[1.2564213055, -6.158132184, -2.448131585]|
|vector3 |[-5.184321865, 5.1481355498, 8.5481513218]|
+--------+------------------------------------------+

看着没啥区别,但是数据类型已经变成array了。

Step3:使用concat_ws函数,合并所有的列

/**
 * 使用concat_ws函数,组合新的列,并指定连接符为“|”
*/
Dataset<Row> result = arrayData.selectExpr("concat_ws('|', vectorId, vec2array) as concatCol");

打印数据格式可以看到

result.printSchema();
root
 |-- concatCol: string (nullable = false)


result.show(false);
+----------------------------------------------+
|concatCol                                     |
+----------------------------------------------+
|vector1|0.2564752136|-2.154645158|0.2648491548|
|vector2|1.2564213055|-6.158132184|-2.448131585|
|vector3|-5.184321865|5.1481355498|8.5481513218|
+----------------------------------------------+

Step4、保存数据

/**
 * 使用Dataset的Savemode任意保存
*/
 result.write().mode(SaveMode.Overwrite).text("/Your/HDFS/Path/");

问题解决!

 

完整代码:

public static void main(String[] args) {
        SparkSession sparkSession = SparkSession
                .builder()
                .master("local[3]")
                .appName("VectorExample")
                .getOrCreate();

        /**
         * 准备数据
         */
        List<Row> data = Arrays.asList(
                RowFactory.create("vector1", Vectors.dense(0.2564752136, -2.154645158, 0.2648491548)),
                RowFactory.create("vector2", Vectors.dense(1.2564213055, -6.158132184, -2.448131585)),
                RowFactory.create("vector3", Vectors.dense(-5.184321865, 5.1481355498, 8.5481513218))
        );
        StructType schema = createStructType(new StructField[]{
                createStructField("vectorId", DataTypes.StringType, false),
                createStructField("vector", new VectorUDT(), false)
        });
        Dataset<Row> dataset = sparkSession.createDataFrame(data, schema);

        /**
         * 定义UDF函数,将vector转为Array数组
         */
        UserDefinedFunction vector2Array = udf((UDF1<Vector, double[]>) vector -> vector.toArray(), DataTypes.createArrayType(DataTypes.DoubleType));

        Dataset<Row> arrayData = dataset.withColumn("vec2array", vector2Array.apply(dataset.col("vector")))
                .select("vectorId", new String[]{"vec2array"});

        /**
         * 使用concat_ws函数,组合新的列,并指定连接符为“|”
         */
        Dataset<Row> result = arrayData.selectExpr("concat_ws('|', vectorId, vec2array) as concatCol");
        result.printSchema();
        result.show(false);

        /**
         * 使用Dataset的Savemode任意保存
         */
        result.write().mode(SaveMode.Overwrite).text("/Your/HDFS/Path/");

    }

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值