Delta lake with Java--liquid clustering

网上说liquid clustering还是实验阶段,python和scala有对应的函数,java没有,只能用sql语句来建表,尝试了两天,遇到很奇怪的情况,先上代码:

import io.delta.tables.DeltaTable;
import org.apache.spark.sql.*;
import org.apache.spark.sql.types.DataTypes;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

public class DeltaLakeCluster {
    //将字符串转换成java.sql.Timestamp
    public static java.sql.Timestamp strToSqlDate(String strDate, String dateFormat) {
        SimpleDateFormat sf = new SimpleDateFormat(dateFormat);
        Date date = null;
        try {
            date = sf.parse(strDate);
        } catch (Exception e) {
            e.printStackTrace();
        }
        java.sql.Timestamp dateSQL = new java.sql.Timestamp(date.getTime());
        return dateSQL;
    }

    public static void main(String[] args) {
        SparkSession spark = SparkSession.builder()
                .master("local[*]")
                .appName("delta_lake")
                .config("spark.sql.extensions", "io.delta.sql.DeltaSparkSessionExtension")
                .config("spark.databricks.delta.autoCompact.enabled", "true")
                .config("spark.databricks.delta.clusteredTable.enableClusteringTablePreview", "true")
                .config("spark.sql.catalog.spark_catalog", "org.apache.spark.sql.delta.catalog.DeltaCatalog")
                .getOrCreate();


        String savePath="D:\\bigdata\\detla-lake-with-java\\YellowTaxi";
        String tableName = "taxidb.YellowTaxis";
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");


        String savePath2="file:///D:\\\\bigdata\\\\detla-lake-with-java\\\\YellowTaxiCluster";
        String tableName2 = "taxidb.YellowTaxisCluster";

        String savePath3="D:\\bigdata\\detla-lake-with-java\\YellowTaxi";

        spark.sql("CREATE DATABASE IF NOT EXISTS taxidb");

        //定义表
        DeltaTable.createIfNotExists(spark)
                .tableName(tableName)
                .addColumn("RideId","INT")
                .addColumn("VendorId","INT")
                .addColumn("PickupTime","TIMESTAMP")
                .addColumn("DropTime","TIMESTAMP")
                .location(savePath)
                .execute();

        //建表只能运行一次,没有办法判断是否存在
        String sqlText="CREATE TABLE IF NOT EXISTS "+tableName2+" USING DELTA CLUSTER BY (VendorId) LOCATION '"+savePath2+"' AS SELECT * FROM "+tableName+"";
        spark.sql(sqlText);

        DeltaTable deltaTable = DeltaTable.forPath(spark,savePath2);
        deltaTable.detail().show(false);
        var schema=deltaTable.toDF().schema();
        //插入数据
        List<Row> list = new ArrayList<Row>();
        list.add(RowFactory.create(-1,-1,strToSqlDate("2023-01-01 10:00:00","yyyy-MM-dd HH:mm:ss"),strToSqlDate("2023-01-01 10:00:00","yyyy-MM-dd HH:mm:ss")));
        var yellowTaxipDF=spark.createDataFrame(list,schema);//建立需要新增数据并转换成dataframe
        System.out.println("插入数据,开始时间"+  sdf.format(new Date()));
        yellowTaxipDF.write().format("delta").mode(SaveMode.Append).saveAsTable(tableName);
        System.out.println("插入数据,结束时间"+  sdf.format(new Date()));
        System.out.println("插入后数据");
        deltaTable.toDF().select("*").where("RideId=-1").show(false);



        //更新数据
        System.out.println("更新前数据");
        deltaTable.toDF().select("*").where("RideId=-1").show(false);
        System.out.println("更新数据,开始时间"+  sdf.format(new Date()));
        deltaTable.update(
                functions.col("RideId").equalTo("-1"),
                new HashMap<String, Column>() {{
                    put("PickupTime", functions.lit("2023-11-01 10:00:00").cast(DataTypes.TimestampType));
                }}
        );
        System.out.println("更新数据,结束时间"+  sdf.format(new Date()));
        System.out.println("更新后数据");
        deltaTable.toDF().select("*").where("RideId=-1").show(false);

        //删除数据
        System.out.println("删除数据,开始时间"+  sdf.format(new Date()));
        deltaTable.delete("RideId=1");
        System.out.println("删除数据,结束时间"+  sdf.format(new Date()));
        deltaTable.toDF().select("*").where("RideId=1").show(false);


        //查询数据
        System.out.println("不分区表查询数据,开始时间"+  sdf.format(new Date()));
        spark.read().format("delta").load(savePath3).where("VendorId==4 and RideId==859744").show(false);
        System.out.println("不分区表查询数据,结束时间" + sdf.format(new Date()));


        System.out.println("分类表查询数据,开始时间"+  sdf.format(new Date()));
        spark.read().format("delta").load(savePath2).where("VendorId==4 and RideId==859744").show(false);
        System.out.println("分类表查询数据,结束时间" + sdf.format(new Date()));



    }
}

第一个遇到的情况,不能像之前那样逐列定义表,即使用sql语句也不行,一定要从另外一个表select数据才能建表成功,具体见代码中sqlText定义。

第二个遇到的情况,判断表是否存在不生效,所以建表的sql运行完第一次后要注释掉否则就会报错。

最终运行结果:

比较一下查询效率,好像没有什么区别,也不知道是不是我的代码有问题,还是本身还是实验阶段。先记录下来,后面继续跟进学习。

  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
K-means聚类算法是一种常用的无监督学习算法,可以将数据集划分为K个不同的类别,每个类别由其质心表示。Java实现K-means聚类算法的步骤如下: 1. 随机选择K个数据点作为初始质心,可以使用java.util.Random类实现随机选择。 2. 根据初始质心,将数据点分配到最近的质心所在的类别中。可以使用欧几里得距离或曼哈顿距离等方式计算数据点到各个质心的距离,然后将数据点分配到距离最近的质心所在的类别中。 3. 计算每个类别的质心,即所有数据点的坐标平均值。可以使用java.util.stream包中的方法对数据点进行求和和计数,然后计算坐标平均值。 4. 重复第2步和第3步,直到质心不再改变或达到最大迭代次数。 下面是Java代码实现K-means聚类算法的示例: ```java import java.util.*; public class KMeans { private List<Point> data; // 数据集 private int k; // 类别数 private List<Point> centers; // 质心集合 public KMeans(List<Point> data, int k) { this.data = data; this.k = k; centers = new ArrayList<>(); } // 初始化质心 private void initCenters() { Random random = new Random(); for (int i = 0; i < k; i++) { Point center = data.get(random.nextInt(data.size())); centers.add(center); } } // 分配数据点到最近的质心所在的类别中 private void assignPoints() { for (Point point : data) { double minDistance = Double.MAX_VALUE; int minIndex = 0; for (int i = 0; i < k; i++) { double distance = point.distance(centers.get(i)); if (distance < minDistance) { minDistance = distance; minIndex = i; } } point.setCluster(minIndex); } } // 计算每个类别的质心 private void computeCenters() { for (int i = 0; i < k; i++) { List<Point> points = new ArrayList<>(); for (Point point : data) { if (point.getCluster() == i) { points.add(point); } } Point center = Point.mean(points); centers.set(i, center); } } // 聚类 public void cluster() { initCenters(); int maxIter = 100; int iter = 0; double epsilon = 0.001; double prevCost = Double.MAX_VALUE; while (iter < maxIter) { assignPoints(); computeCenters(); double cost = cost(); if (Math.abs(cost - prevCost) < epsilon) { break; } prevCost = cost; iter++; } } // 计算聚类代价 private double cost() { double cost = 0; for (Point point : data) { Point center = centers.get(point.getCluster()); cost += point.distance(center); } return cost; } } ``` 其中,Point类表示一个数据点,包含x、y坐标和所属的类别;mean方法表示计算一组数据点的坐标平均值。可以根据具体应用场景修改代码实现。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值