spark(七):DataSet

說明

本博客週五更新 本文記錄spark 分佈式數據類型DataSet的基本原理和使用方法。 DataSet是Spark1.6添加的分佈式數據集合,Spark2.0合併DataSet和DataFrame數據集合API,DataFrame變成DataSet的子集。 DataSet繼承RDD優點,並使用Spark SQL優化的執行引擎。支持JVM對象構建,支持函數式轉換(map/flatmap/filter)等多種操作

資料

優勢

  • 靜態類型和運行時類型檢查,編譯時檢查類型,避免程序運行中因類型錯誤造成任務失敗。
  • High-level抽象以及結構化半結構化數據集的自定義視圖
    • DataFrame是Dataset[Row]的集合,把結構化數據集視圖轉換成半結構化數據集。例如,有個海量IoT設備事件數據集,用JSON格式表示。JSON是一個半結構化數據格式,很適合使用Dataset, 轉成強類型的Dataset[DeviceIoTData]。
  • 簡單易用的API
    • 結構化數據給spark程序操作數據集帶來很多限制,同時也引入了豐富的語義和易用的特定領域語言,如filter()、map()等。
  • 性能和優化
    • 因爲Spark DataFrame和DataSet構建於Spark SQL引擎紙上,它會使用Catalys優化器生成優化的邏輯計劃和物理查詢計劃任務,以帶來空間和速度上的提升。

代碼實例

  • java版DataSet方式操作數據,測試數據爲|分隔,共6個字段:date、name、condition、city、platform、version,類型string。
public class WordPro {
	private static SparkSession gloableSpark;
	private static Logger logger = LoggerFactory.getLogger(WordPro.class);
 
	public static void main(String[] args) {
		//獲取sparkSession
		SparkSession spark = SparkSession.builder().appName("wordPro").master("local[4]").getOrCreate();
		gloableSpark = spark;
		JavaRDD<Row> rowRDD = spark.read().text("D:\\data\\sparksql\\pro\\keyword.txt").toJavaRDD();
		logger.info("完整數據:");
		rowRDD.collect().forEach(line -> System.out.println(line));
 
		//將長度不符合規範的數據先過濾掉
		JavaRDD<Row> programRdd = rowRDD.filter(new Function<Row, Boolean>() {
			private static final long serialVersionUID = 975739302260154160L;
 
			@Override
			public Boolean call(Row v1) throws Exception {
				boolean result = v1.get(0).toString().split("\\|").length == 6;
				return result;
			}
		}).map(new Function<Row, Row>() {
			//將數據根據tab進行拆分重組成爲符合StructType的JavaRdd<Row>
			@Override
			public Row call(Row v1) throws Exception {
				String[] datas = v1.get(0).toString().split("\\|");
				Row row = RowFactory.create(
						datas[0],
						datas[1],
						datas[2],
						datas[3],
						datas[4],
						datas[5]
				);
				return row;
			}
		});
		//根據StructField來創建StructType
		List<StructField> structFieldList = new ArrayList<>();
		structFieldList.add(DataTypes.createStructField("date", DataTypes.StringType, true));
		structFieldList.add(DataTypes.createStructField("name", DataTypes.StringType, true));
		structFieldList.add(DataTypes.createStructField("condition", DataTypes.StringType, true));
		structFieldList.add(DataTypes.createStructField("city", DataTypes.StringType, true));
		structFieldList.add(DataTypes.createStructField("platform", DataTypes.StringType, true));
		structFieldList.add(DataTypes.createStructField("version", DataTypes.StringType, true));
		StructType structType = DataTypes.createStructType(structFieldList);
		//通過structType將rdd轉換爲Dataset
		Dataset<Row> infoDataset = spark.createDataFrame(programRdd, structType);
		//創建臨時表
		infoDataset.createOrReplaceTempView("info");
		//構造查詢條件
		Map<String, String> params = new HashMap<>(2);
		params.put("city", "nanjing");
		selectByCondition(params);
	}
 
	private static void selectByCondition(Map<String, String> params) {
		String city = params.get("city");
		String platform = params.get("platform");
		//拼接查詢sql
		StringBuffer sqlBuffer = new StringBuffer("select * from info where 1=1 ");
		sqlBuffer = city == null ? sqlBuffer : sqlBuffer.append(" and city = '" + city + "'");
		sqlBuffer = platform == null ? sqlBuffer : sqlBuffer.append(" and platform = '" + platform + "'");
		String sql = sqlBuffer.toString();
		logger.info("查詢sql:" + sql);
		gloableSpark.sql(sql).show();
	}
}

DataFrame和DataSet的區別

  • DataFrame 一行記錄中沒有指定特定的數據類型
  • Dataset 一行記錄中每個對象有明確類型

總結

  • DataSet在DataFrame基礎上支持更強的數據類型控制,更精細化操作數據,避免因數據類型異常,造成的程序運行異常。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章