স্পার্ক> = 2.3.0
স্পার্ক -22614 পরিসীমা বিভাজন প্রকাশ করে।
val partitionedByRange = df.repartitionByRange(42, $"k")
partitionedByRange.explain
// == Parsed Logical Plan ==
// 'RepartitionByExpression ['k ASC NULLS FIRST], 42
// +- AnalysisBarrier Project [_1#2 AS k#5, _2#3 AS v#6]
//
// == Analyzed Logical Plan ==
// k: string, v: int
// RepartitionByExpression [k#5 ASC NULLS FIRST], 42
// +- Project [_1#2 AS k#5, _2#3 AS v#6]
// +- LocalRelation [_1#2, _2#3]
//
// == Optimized Logical Plan ==
// RepartitionByExpression [k#5 ASC NULLS FIRST], 42
// +- LocalRelation [k#5, v#6]
//
// == Physical Plan ==
// Exchange rangepartitioning(k#5 ASC NULLS FIRST, 42)
// +- LocalTableScan [k#5, v#6]
স্পার্ক -22389 ডেটা সোর্স এপিআই ভি 2 -তে বাহ্যিক ফর্ম্যাট পার্টিশনটি প্রকাশ করে ।
স্পার্ক> = 1.6.0
স্পার্ক> = 1.6 এ কোয়েরি এবং ক্যাশিংয়ের জন্য কলাম দ্বারা বিভাজন ব্যবহার করা সম্ভব। দেখুন: পদ্ধতিটি ব্যবহার করে স্পার্ক -11410 এবং স্পার্ক -4849repartition
:
val df = Seq(
("A", 1), ("B", 2), ("A", 3), ("C", 1)
).toDF("k", "v")
val partitioned = df.repartition($"k")
partitioned.explain
// scala> df.repartition($"k").explain(true)
// == Parsed Logical Plan ==
// 'RepartitionByExpression ['k], None
// +- Project [_1#5 AS k#7,_2#6 AS v#8]
// +- LogicalRDD [_1#5,_2#6], MapPartitionsRDD[3] at rddToDataFrameHolder at <console>:27
//
// == Analyzed Logical Plan ==
// k: string, v: int
// RepartitionByExpression [k#7], None
// +- Project [_1#5 AS k#7,_2#6 AS v#8]
// +- LogicalRDD [_1#5,_2#6], MapPartitionsRDD[3] at rddToDataFrameHolder at <console>:27
//
// == Optimized Logical Plan ==
// RepartitionByExpression [k#7], None
// +- Project [_1#5 AS k#7,_2#6 AS v#8]
// +- LogicalRDD [_1#5,_2#6], MapPartitionsRDD[3] at rddToDataFrameHolder at <console>:27
//
// == Physical Plan ==
// TungstenExchange hashpartitioning(k#7,200), None
// +- Project [_1#5 AS k#7,_2#6 AS v#8]
// +- Scan PhysicalRDD[_1#5,_2#6]
RDDs
স্পার্কের বিপরীতে Dataset
( Dataset[Row]
ওরফে সহ DataFrame
) এখন পর্যন্ত কাস্টম বিভাজনকারী ব্যবহার করতে পারবেন না। আপনি কৃত্রিম বিভাজন কলাম তৈরি করে সাধারণত এটি সম্বোধন করতে পারেন তবে এটি আপনাকে একই নমনীয়তা দেয় না।
স্পার্ক <1.6.0:
একটি জিনিস আপনি যা করতে পারেন তা হ'ল প্রাক-পার্টিশন ইনপুট ডেটা তৈরির আগে DataFrame
import org.apache.spark.sql.types._
import org.apache.spark.sql.Row
import org.apache.spark.HashPartitioner
val schema = StructType(Seq(
StructField("x", StringType, false),
StructField("y", LongType, false),
StructField("z", DoubleType, false)
))
val rdd = sc.parallelize(Seq(
Row("foo", 1L, 0.5), Row("bar", 0L, 0.0), Row("??", -1L, 2.0),
Row("foo", -1L, 0.0), Row("??", 3L, 0.6), Row("bar", -3L, 0.99)
))
val partitioner = new HashPartitioner(5)
val partitioned = rdd.map(r => (r.getString(0), r))
.partitionBy(partitioner)
.values
val df = sqlContext.createDataFrame(partitioned, schema)
যেহেতু DataFrame
একটি থেকে তৈরি করতে RDD
কেবলমাত্র একটি সাধারণ মানচিত্রের পর্যায়ে বিদ্যমান পার্টিশন লেআউটটি সংরক্ষণ করা উচিত *:
assert(df.rdd.partitions == partitioned.partitions)
আপনি যেভাবে পুনরায় বিভাজন করতে পারেন একইভাবে DataFrame
:
sqlContext.createDataFrame(
df.rdd.map(r => (r.getInt(1), r)).partitionBy(partitioner).values,
df.schema
)
সুতরাং দেখে মনে হচ্ছে এটি অসম্ভব নয়। প্রশ্নটি যদি আদৌ বোঝায় তা থেকে যায়। আমি যুক্তি দেব যে বেশিরভাগ সময় এটি হয় না:
পুনঃবিভাজন একটি ব্যয়বহুল প্রক্রিয়া। একটি সাধারণ দৃশ্যে বেশিরভাগ ডেটা সিরিয়ালাইজড, বদলানো এবং ডিসিরিয়ালাইজড করতে হয়। অপরদিকে অপারেশনগুলির সংখ্যা যা পূর্ব-বিভাজিত ডেটা থেকে উপকার পেতে পারে তা তুলনামূলকভাবে কম এবং যদি অভ্যন্তরীণ এপিআই এই সম্পত্তিটি উত্তোলনের জন্য ডিজাইন না করা হয় তবে আরও সীমাবদ্ধ।
- কিছু পরিস্থিতিতে যোগ দেয়, তবে এটির জন্য অভ্যন্তরীণ সহায়তা প্রয়োজন,
- উইন্ডো ফাংশন মেলা বিভাজক সঙ্গে কল। উপরের মত একই, একক উইন্ডো সংজ্ঞাতে সীমাবদ্ধ। এটি ইতিমধ্যে অভ্যন্তরীণভাবে বিভক্ত হয়েছে, সুতরাং প্রাক-বিভাজন অপ্রয়োজনীয় হতে পারে,
- এর সাথে সরল সমষ্টি
GROUP BY
- অস্থায়ী বাফারগুলির ** মেমরির পদচিহ্ন হ্রাস করা সম্ভব তবে সামগ্রিক ব্যয় অনেক বেশি। কমবেশি groupByKey.mapValues(_.reduce)
(বর্তমান আচরণ) বনাম reduceByKey
(পূর্ব-পার্টিশন) এর সমান । অনুশীলনে কার্যকর হতে পারে না।
- সঙ্গে ডেটা সংকোচনের
SqlContext.cacheTable
। যেহেতু দেখে মনে হচ্ছে এটি রান দৈর্ঘ্যের এনকোডিং ব্যবহার করছে, প্রয়োগ করা OrderedRDDFunctions.repartitionAndSortWithinPartitions
সংক্ষেপণের অনুপাতকে উন্নত করতে পারে।
পারফরম্যান্স কীগুলি বিতরণের উপর অত্যন্ত নির্ভরশীল। যদি এটি স্কিউ করা হয় তবে এর ফলে সাবপটিমাল রিসোর্স ব্যবহার হবে। সবচেয়ে খারাপ পরিস্থিতিতে দৃশ্যে কাজটি শেষ করা মোটেও অসম্ভব।
- উচ্চ স্তরের ঘোষণামূলক এপিআই ব্যবহারের সম্পূর্ণ পয়েন্টটি হ'ল নিম্ন স্তরের প্রয়োগের বিশদ থেকে নিজেকে বিচ্ছিন্ন করা। @Dwysakowicz এবং @RomiKuntsman দ্বারা ইতিমধ্যে উল্লিখিত হিসাবে একটি অপ্টিমাইজেশন ক্যাটালিস্ট অপ্টিমাইজারের কাজ । এটি একটি সুন্দর পরিশীলিত জন্তু এবং আমি সত্যিই সন্দেহ করি যে এর অভ্যন্তরের অভ্যন্তরে গভীর গভীরতা না ডেকেই আপনি সহজেই এর উন্নতি করতে পারেন।
সম্পর্কিত ধারণা
জেডিবিসি সূত্রগুলির সাথে বিভাজন :
জেডিবিসি ডেটা সূত্রগুলি predicates
যুক্তি সমর্থন করে । এটি নিম্নলিখিত হিসাবে ব্যবহার করা যেতে পারে:
sqlContext.read.jdbc(url, table, Array("foo = 1", "foo = 3"), props)
এটি পূর্বাভাস অনুযায়ী একক জেডিবিসি পার্টিশন তৈরি করে। মনে রাখবেন যে পৃথক পূর্বাভাসগুলি ব্যবহার করে তৈরি সেটগুলি যদি বিঘ্নিত না হয় তবে আপনি ফলাফল সারণিতে নকল দেখতে পাবেন।
partitionBy
পদ্ধতিতেDataFrameWriter
:
স্পার্ক DataFrameWriter
একটি partitionBy
পদ্ধতি প্রদান করে যা লেখার ক্ষেত্রে "পার্টিশন" ডেটা ব্যবহার করতে পারে। এটি প্রদত্ত কলামগুলির সেট ব্যবহার করে লেখার ডেটা পৃথক করে
val df = Seq(
("foo", 1.0), ("bar", 2.0), ("foo", 1.5), ("bar", 2.6)
).toDF("k", "v")
df.write.partitionBy("k").json("/tmp/foo.json")
এটি কী-এর উপর ভিত্তি করে প্রশ্নের জন্য পঠন-পাঠের প্রস্তাবটিকে সক্ষম করে:
val df1 = sqlContext.read.schema(df.schema).json("/tmp/foo.json")
df1.where($"k" === "bar")
তবে এটি সমান নয় DataFrame.repartition
। বিশেষ একত্রিতে যেমন:
val cnts = df1.groupBy($"k").sum()
এখনও প্রয়োজন হবে TungstenExchange
:
cnts.explain
// == Physical Plan ==
// TungstenAggregate(key=[k#90], functions=[(sum(v#91),mode=Final,isDistinct=false)], output=[k#90,sum(v)#93])
// +- TungstenExchange hashpartitioning(k#90,200), None
// +- TungstenAggregate(key=[k#90], functions=[(sum(v#91),mode=Partial,isDistinct=false)], output=[k#90,sum#99])
// +- Scan JSONRelation[k#90,v#91] InputPaths: file:/tmp/foo.json
bucketBy
পদ্ধতিতে DataFrameWriter
(স্পার্ক> = ২.০):
bucketBy
অনুরূপ অ্যাপ্লিকেশন রয়েছে partitionBy
তবে এটি কেবল টেবিলগুলির জন্য উপলব্ধ ( saveAsTable
)। বুকিংয়ের তথ্যগুলি যোগদানের অনুকূলিত করতে ব্যবহার করতে পারে:
// Temporarily disable broadcast joins
spark.conf.set("spark.sql.autoBroadcastJoinThreshold", -1)
df.write.bucketBy(42, "k").saveAsTable("df1")
val df2 = Seq(("A", -1.0), ("B", 2.0)).toDF("k", "v2")
df2.write.bucketBy(42, "k").saveAsTable("df2")
// == Physical Plan ==
// *Project [k#41, v#42, v2#47]
// +- *SortMergeJoin [k#41], [k#46], Inner
// :- *Sort [k#41 ASC NULLS FIRST], false, 0
// : +- *Project [k#41, v#42]
// : +- *Filter isnotnull(k#41)
// : +- *FileScan parquet default.df1[k#41,v#42] Batched: true, Format: Parquet, Location: InMemoryFileIndex[file:/spark-warehouse/df1], PartitionFilters: [], PushedFilters: [IsNotNull(k)], ReadSchema: struct<k:string,v:int>
// +- *Sort [k#46 ASC NULLS FIRST], false, 0
// +- *Project [k#46, v2#47]
// +- *Filter isnotnull(k#46)
// +- *FileScan parquet default.df2[k#46,v2#47] Batched: true, Format: Parquet, Location: InMemoryFileIndex[file:/spark-warehouse/df2], PartitionFilters: [], PushedFilters: [IsNotNull(k)], ReadSchema: struct<k:string,v2:double>
* পার্টিশন লেআউট দ্বারা আমি কেবল একটি ডেটা বন্টন বোঝাতে চাইছি। partitioned
আরডিডি-র আর কোনও বিভাজন নেই। ** প্রাথমিক প্রজেকশন ধরে নিচ্ছি না। সমষ্টি যদি কলামগুলির কেবলমাত্র ছোট উপসেটকে কভার করে তবে সম্ভবত কোনও লাভ নেই।