スパーク統合
、スパークアーキテクチャとオプティマイザ
1.Sparkアーキテクチャ(フォーカス)
- 既存のデータ(メタデータリンクハイブアドレッシング)へのハイブの直接アクセス
- スパークによるデータ処理のためのサードパーティ製のツールのためのJDBC / ODBCインタフェースを提供します
- 便利にデータを処理するために高レベルのインターフェイスを提供する(SQL演算子、データフレームのクラス)
- SQL、APIプログラミング(スパーク-SQL、火花シェル、スパークAPI):複数のオペレーティングモードのサポート
- これは、外部データソースの様々なサポートしています。寄木張り、JSON、RDBMS、CSV、テキスト、ハイブ、HBaseのなど
2.Sparkオプティマイザ
メタデータ・アナライザ・モジュールによって論理プランに解決未解決の論理計画;今回は、ルールベースの最適化戦略の多様経由で、深行うためにパーサモジュールによる最初のSQL文は、このツリーは、未解決の論理計画と呼ばれ、構文木を解析されます最適化、最適化された論理的な計画を取得し、ロジックの実装計画は、まだ最適化されたロジックで、スパークシステムを理解すべきではない、あなたは物理計画のために、このロジックの実装計画を変換する必要があります。
-
最適化
1、クエリフィルタ2以上の投影において、加圧濾過するかどうかをチェックします
二、スパーク+ SQLのAPI (フォーカス)
はじめに:実際にはスパーク、ハイブは、メタデータベースとデータウェアハウスによって維持、スキーマデータのメンテナンスと同様有しており、データフレームは、SQL直接スキーマ・データを操作することができ提供、スキーマとデータのRDDクラスパッケージでありますインターフェース、およびダイレクト分析関数のSQLネイティブSQLステートメントを提供します。一方、スパークはまた、メタストアのJDBCインターフェースまたは外部メタデータ・データベースへのインタフェースリンクのハイブ、データベースは、ハイブへのデータウェアハウスとRDBMSにこのメタデータ操作によって実現されることができます。
-
SparkContext
-
SQLContext
- スパークSQLプログラミングエントリー
-
HiveContext
- SQLContextサブセットは、より多くの機能が含まれています
-
SparkSession(スパーク2.xの推奨)
- SparkSession:SQLContextはHiveContextと合併しました
- スパークは、インタラクティブな機能を単一のエントリポイントを提供し、データフレームデータセットのAPIとプログラミングスパークの使用が可能
-------------------------------------------
1.DataSetプロフィール
特定のドメインオブジェクト(配列、配列、RDD)で強く型付けされたコレクションに基づくRDDは、最大の違いは、RDDということです:DSは、データ構造のスキーマ情報を持っています。データセット= RDD +スキーマ
- すなわち、データセットスキーマデータ構造情報データセット(行列)の
scala> spark.createDataset(1 to 3).show
scala> spark.createDataset(List(("a",1),("b",2),("c",3))).show
scala> spark.createDataset(sc.parallelize(List(("a",1,1),("b",2,2)))).show
- CreateDataSet()パラメータがあってもよい:配列、配列、RDD
- 上記の3つの行が生成されるデータセット:データセット[INT]、データセット[(文字列、INT)]、データセット[(文字列、INT、INT)]
- データセット= RDD +スキーマなどなどマップ、フィルタ、などのデータセットRDD最も一般的な機能、
-------------------------------------------
2.DataFrameプロフィール
DSに基づいていますが、要素が限られているために、クラス行]操作はこのように、多くの場合より3倍速いDSより最適化DF、DFの操作を標的とすることができるように定義されています、。SQLの行同等の記録
データフレーム= EET [ROW] +スキーマ
-
データフレーム=データセット[行]
-
従来の2次元データテーブルと同様に
-
加え(データ構成情報)に基づいてRDDスキーマ
-
データフレームのスキーマをサポートし、ネストされたデータ型を
- 対応するHBaseの大きなデータ構造、リソース消費
- 構造体
- 地図
- アレイ
-
、より多くのSQLに似た操作のAPIを提供するパラメータとして、SQL文のSQLクエリを使用するために、このような直接的な演算子として:
df.sql("select * from table_name")
-------------------------------------------
3.RDDとのDF / DSを作成します
このスキーマはどのようなものです:
- RDDにDS / DF変換
case class Point(label:String,x:Double,y:Double)
val points=Seq(Point("bar",3.0,5.6),Point("foo",-1.0,3.0)).toDF("label","x","y")
//转换
val s=points.rdd
-
DSやDFのためのRDD組織
- toDF /トッズオペレーター
- この方法は、データタイプのスキーマザRDD内部反射情報を自動的に推論生成します
case class Person(name:String,age:Int)
//反射获取RDD内的样例类的Schema来构造DF
import spark.implicits._
val people=sc.textFile("file:///home/hadooop/data/people.txt")
.map(_.split(","))
.map(p => Person(p(0), p(1).trim.toInt)).toDF() ////map构造实例类,toDS或者toDF方法
people.show
people.registerTempTable("people") //将DF注册为临时表,以使用sql语句
val teenagers = spark.sql("SELECT name, age FROM people WHERE age >= 13 AND age <= 19")
teenagers.show()
//也可以不定义样例类直接使用Array、Seq等集合的toDF方法,参数给定为列名,类型会自动推断
-
定義DF DF +スキーマで構成する(フォーカス)
問題と形式のデータヘッダの読み取りの問題に対処するための暗黙の必要性は、テキストの書式設定sc.textfile
spark.read。フォーマットは自動的に解決フォーマットフィールドに変換することができない、すべての文字列
だから我々は、事前に定義されたスキーマの再読み込み方法を通じて、複雑なデータ型変換の問題を解決します
すべてのフィールドが必要であると仮定すると、追加のフィールド定義は気にしないためにそれ以外の場合は必要
import org.apache.spark.sql.Row import org.apache.spark.sql.types.{StructType, StructField, StringType} val myschema=new StructType().add("order_id",StringType).add("order_date",StringType).add("customer_id",StringType).add("status",StringType) val orders=spark.read.schema(myschema).csv("file:///root/orders.csv")
-
DF(に適用することによりROW +スキーマ組織生データの外部ソース)
//构造ROW对象和指定Schema的方法组合 people=sc.textFile("file:///home/hadoop/data/people.txt") val schemaString = "name age" // 以字符串的方式定义DataFrame的Schema信息 import org.apache.spark.sql.Row import org.apache.spark.sql.types.{StructType, StructField, StringType} // StructType类自定义Schema val schema = StructType(schemaString.split(" ").map(fieldName =>StructField(fieldName,StringType, true))) //类型是Arrayp[StructField] //Row类包装数据内容 val rowRDD = people.map(_.split(",")).map(p => Row(p(0), p(1).trim)) // 创建DF类,参数为Row类和StructType类 val peopleDataFrame = spark.createDataFrame(rowRDD, schema) // 将DataFrame注册成临时表 peopleDataFrame.registerTempTable("people") val results = spark.sql("SELECT name FROM people") results.show
-------------------------------------------
4.一般的な操作
//引用select
ds.select("name")
ds.select(ds("name"))
ds.select(col("name"))
ds.select(column("name"))
ds.select('name')
ds.select($"name")
//统计指标
df.describe("colname").show()
//日期处理类(JAVA)
import java.time.LocalDate
import java.time.format.DateTimeFormatter
LocalDate.parse("2018-08-01 12:22:21", DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss")).getDayOfWeek
//包装这个JAVA方法为scala函数,方便使用
def TimeParse(x:String):String={
LocalDate.parse(x,DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss")).getDayOfWeek.toString
}
//join操作,列比较时使用三元符号===
val joined=orderDS.join(order_itemsDS,orderDS("id")===order_itemsDS("order_id"))
//常见操作
val df = spark.read.json("file:///home/hadoop/data/people.json")
// 使用printSchema方法输出DataFrame的Schema信息
df.printSchema()
// 使用select方法来选择我们所需要的字段
df.select("name").show()
// 使用select方法选择我们所需要的字段,并未age字段加1!!!!!!!!!!!!!!
df.select(df("name"), df("age") + 1).show()
// 使用filter方法完成条件过滤
df.filter(df("age") > 21).show()
// 使用groupBy方法进行分组,求分组后的总数
df.groupBy("age").count().show()
//sql()方法执行SQL查询操作
df.registerTempTable("people") //先要将df注册为临时表
spark.sql("SELECT * FROM people").show //直接在sql中查询注册的表
図5に示すように、型変換
フィールドは、文字列のメソッドを取得するために型変換の必要性を読んでいます
//1、单列转化方法
import org.apache.spark.sql.types._
val data = Array(("1", "2", "3", "4", "5"), ("6", "7", "8", "9", "10"))
val df = spark.createDataFrame(data).toDF("col1", "col2", "col3", "col4", "col5")
import org.apache.spark.sql.functions._
df.select(col("col1").cast(DoubleType)).show()
+----+
|col1|
+----+
| 1.0|
| 6.0|
+----+
//2、循环转变
//然后就想能不能用这个方法循环把每一列转成double,但没想到怎么实现,可以用withColumn循环实现。
val colNames = df.columns
var df1 = df
for (colName <- colNames) {
df1 = df1.withColumn(colName, col(colName).cast(DoubleType))
}
df1.show()
+----+----+----+----+----+
|col1|col2|col3|col4|col5|
+----+----+----+----+----+
| 1.0| 2.0| 3.0| 4.0| 5.0|
| 6.0| 7.0| 8.0| 9.0|10.0|
+----+----+----+----+----+
//3、通过:_*
//但是上面这个方法效率比较低,然后问了一下别人,发现scala 有array:_*这样传参这种语法,而df的select方法也支持这样传,于是最终可以按下面的这样写
val cols = df.columns.map(x => col(x).cast("Double"))
df.select(cols: _*).show()
+----+----+----+----+----+
|col1|col2|col3|col4|col5|
+----+----+----+----+----+
| 1.0| 2.0| 3.0| 4.0| 5.0|
| 6.0| 7.0| 8.0| 9.0|10.0|
+----+----+----+----+----+
//这样就可以很方便的查询指定多列和转变指定列的类型了:
val name = "col1,col3,col5"
df.select(name.split(",").map(name => col(name)): _*).show()
df.select(name.split(",").map(name => col(name).cast(DoubleType)): _*).show()
三、スパーク外部データソース動作(フォーカス)
1.Parquetファイル(デフォルトのファイル)
人気のカラムストレージにフォーマットバイナリ記憶データファイルが含まれているメタデータ(ROWスキーマデータとメタデータ)
import org.apache.spark.sql.types._
val schema=StructType(Array(StructField("name",StringType),
StructField("favorite_color",StringType),
StructField("favorite_numbers",ArrayType(IntegerType))))
val rdd=sc.parallelize(List(("Alyssa",null,Array(3,9,15,20)),("Ben","red",null)))
val rowRDD=rdd.map(p=>Row(p._1,p._2,p._3))
val df=spark.createDataFrame(rowRDD,schema)
val df=spark.read.parquet("/data/users/") //该目录下必须已存在parquet文件
df.write.parquet("/data/users_new/") //在该目录下生成parquet文件
------------------------------------------
2.Hive表
統合されたハイブ:
データベースにライゲート外部インタフェースハイブオープンメタデータ・リポジトリ、スパーク、メタデータ情報ハイブによって取得されたデータ:SQLハイブと統合スパーク。実際には、ハイブメタデータ管理と同じ。
統合テスト環境(シェルの開発)
- オープンハイブのサービスメタストア
#hive打开元数据库的外部接口 9083
nohup hive --service metastore & #nohup 绑定系统,终端退出服务也会运行
- データベース・リンクハイブへのスパーク・シェル
//Spark 链接到hive的元数据库
spark-shell --conf spark.hadoop.hive.metastore.uris=thrift://localhost:9083
//或者,自行建立session
val spark = SparkSession.builder()
.config("spark.sql.warehouse.dir", warehouseLocation)
.enableHiveSupport()
.getOrCreate()
//保存表到hive上
df.saveAsTable("tbl_name")
生成統合環境(IDE開発)
SQLハイブと統合スパーク:confの下で1 2枚のコピーに、ハイブ-site.xmlの、追加のコンテンツを$ / {} SPARK_HOME
<property>
<name>hive.metastore.uris</name>
<value>thrift://master的IP:9083</value>
</property>
(オプション、その設定せずにXMLが自動的にMySQLのJDBCをリンクされている)3、メタデータサービスを開始します。nohupをハイブ--serviceメタストア&4、SparkSessionは倉庫アドレスハイブのサポートを設定し、有効にするために独自のアプリケーションを作成します
val spark = SparkSession.builder()
.config("spark.sql.warehouse.dir", warehouseLocation) //warehouse可选,默认在启动时的目录下
.enableHiveSupport()
.getOrCreate()
ハイブに格納された火花
hive --service metastore
spark-shell
spark.sql("show tables").show
//或者
val df=spark.table("toronto") //返回的是DataFrame类
df.printSchema
df.show
df.write.saveAsTable("dbName.tblName")
//hive
select * from dbName.tblName;
-------------------------------------------
3.MySQLテーブル(MySQLの)
ハイブと統合RDBMSリレーショナルデータベース管理システムは、基本的には同じですが、メタストアサービスのハイブを通過しなかったが、直接のJDBCのMySQLの使用にリンクされています
spark-shell --driver-class-path /opt/hive/lib/mysql-connector-java-5.1.38.jar
val df=spark.read.format("jdbc").option("delimiter",",").option("header","true").option("url","jdbc:mysql://192.168.137.137:3306/test").option("dbtable","orders").option("user","root").option("password","rw").load()
//
$spark-shell --jars /opt/spark/ext_jars/mysql-connector-java-5.1.38.jar //使用jdbc的jar去连RDBMS
val url = "jdbc:mysql://localhost:3306/test" //test是一个数据库名
val tableName = "TBLS" //TBLS是库中的一个表名
// 设置连接用户、密码、数据库驱动类
val prop = new java.util.Properties
prop.setProperty("user","hive")
prop.setProperty("password","mypassword")
prop.setProperty("driver","com.mysql.jdbc.Driver")
// 取得该表数据
val jdbcDF = spark.read.jdbc(url,tableName,prop)
jdbcDF.show
//DF存为新的表
jdbcDF.write.mode("append").jdbc(url,"t1",prop)
四、スパーク+ SQL関数
1 組み込み関数(org.apache.spark.sql.funtions.scala)
- Scalaは関数で、テーブルのための関数のSQLスパーク列を区別する。
- 組み込み関数は、データフレームのためのUDFのハイブではありません
カテゴリ | 関数の例 |
---|---|
集計関数 | COUNTDISTINCT * *、sumDistinct ** |
集約関数 | sort_array * *、**爆発 |
日付と時刻関数 | 時間* *、四半期、NEXT_DAY ** |
数学関数 | ASIN * *、ATAN、SQRT、日焼け、ラウンド** |
ウィンドウ関数 | ROW_NUMBER |
文字列関数 | 連結* *、format_number、regexp_extract ** |
その他の機能 | ますisNaN * *、SHA、関数randn、callUDF ** |
2. カスタム機能
-
定義関数
-
登録機能
- SparkSession.udf.register():のみSQL()の有効(統合のSQLスパーク)
- functions.udf():データフレームのAPI(スパークベースのデータベースRDD)のための有効な
-
関数呼出し
//注册自定义函数,注意是匿名函数
spark.udf.register("hobby_num", (s: String) => s.split(',').size)
spark.sql("select name, hobbies, hobby_num(hobbies) as hobby_num from hobbies").show
五、スパーク-SQL
ハイブムーブR&D人材、したがって火花SQL操作の多くは、ハイブに同様であるため
しかし、スパーク-SQLベースのフレームワークは、MRはないので、速度は非常に高速に比較されます。
- スパークSQL CLIは、単純なコマンドラインクエリツールは、入力されたローカルモードでハイブセルのストレージサービスと実行を使用しているノートを、SQL CLIは倹約JDBCサーバーと通信することができませんスパーク
- SQL CLI等同于ハイブCLI(旧CLI)、ビーラインCLI(新しいCLI)をスパーク
- スパークSQL CLIを起動し、スパークディレクトリで次のように実行します
./bin/spark-sql
第六に、パフォーマンスの最適化
1.シリアル
-
Javaの直列、スパークデフォルト
-
Kryoのシリアライズ、約10倍のJavaのシリアライズよりも速いが、タイプのないすべてのシーケンス
conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer"); //向Kryo注册自定义类型 conf.registerKryoClasses(Array(classOf[MyClass1], classOf[MyClass2]));//case class
無登録に必要なシリアライゼーションクラスが存在しない場合は、KYROは通常どおりに動作することができますが、多くの場合、デフォルトのJavaのシリアライズよりもスペースの無駄である各オブジェクトの完全なクラス名(完全なクラス名)を格納します
2.留意事項
- オブジェクトのアレイ用いてプリミティブ型代わりのJava、Scalaのコレクション(例えば、ハッシュマップ)
- ネストされた避ける構造を
- 使用してくださいキーとして数字ではない文字列を、
- RDDのより一層の活用MEMORY_ONLY_SER
- CSV、JSON、唯一の負荷をロードし、必要なフィールド
- それは中間結果を永続化する必要がある唯一のとき(RDD / DS / DF)
- 不要(RDD / DS / DF)発生を回避するための中間結果
- DF速く実行速度はDSよりも約3倍高速であります
- RDDパーティションとカスタムspark.default.parallelismは、タスクの各段階のデフォルト数を設定します。
- 大きな変数が放送され、代わりに使用して
- ノード間で作業を最小限に抑えるために、ローカルデータ処理とデータ送信をお試しください
表3に接続(結合操作)
- 含まれているすべてのテーブルの述語(述語)
select * from t1 join t2 on t1.name = t2.full_name
where t1.name = 'mike' and t2.full_name = 'mike'
- 最初の場所で最大のテーブル
- ブロードキャスト最小のテーブル
- テーブルの数を最小限に参加