SilverStreamingApplication 1.7__tar.gz → 1.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/PKG-INFO +1 -1
- {silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/com/phida/main/Operations.py +4 -69
- {silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/com/phida/main/SilverMerge.py +81 -47
- {silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/setup.py +1 -1
- {silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/silverstreamingapplication.egg-info/PKG-INFO +1 -1
- {silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/com/phida/main/Maintenance.py +0 -0
- {silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/com/phida/main/PartitionAnalyzer.py +0 -0
- {silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/com/phida/main/PerfAnalyzer.py +0 -0
- {silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/com/phida/main/WorkflowBuilder.py +0 -0
- {silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/com/phida/main/__init__.py +0 -0
- {silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/com/phida/main/logging.py +0 -0
- {silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/com/phida/main/sparksession.py +0 -0
- {silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/com/phida/main/utils.py +0 -0
- {silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/com/phida/main/utilsDatabricksAPI.py +0 -0
- {silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/com/phida/tests/OperationsTest.py +0 -0
- {silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/com/phida/tests/__init__.py +0 -0
- {silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/com/phida/tests/main_test.py +0 -0
- {silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/com/phida/tests/utils_test.py +0 -0
- {silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/setup.cfg +0 -0
- {silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/silverstreamingapplication.egg-info/SOURCES.txt +0 -0
- {silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/silverstreamingapplication.egg-info/dependency_links.txt +0 -0
- {silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/silverstreamingapplication.egg-info/top_level.txt +0 -0
{silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/com/phida/main/Operations.py
RENAMED
|
@@ -2,10 +2,6 @@ from pyspark.sql.utils import AnalysisException
|
|
|
2
2
|
from com.phida.main.sparksession import spark
|
|
3
3
|
from pyspark.sql.functions import col
|
|
4
4
|
from pyspark.sql.types import _parse_datatype_string, StructType, StructField
|
|
5
|
-
#Importing dbutils as it is used in file movement.
|
|
6
|
-
from pyspark.dbutils import DBUtils
|
|
7
|
-
|
|
8
|
-
dbutils = DBUtils(spark.sparkContext)
|
|
9
5
|
|
|
10
6
|
|
|
11
7
|
def tableExists(dbName, tblName):
|
|
@@ -57,30 +53,14 @@ def getKeyCols(dbName, tblName):
|
|
|
57
53
|
"""
|
|
58
54
|
|
|
59
55
|
try:
|
|
60
|
-
|
|
61
|
-
# To achive Below Logic:
|
|
62
|
-
#If Both HVR and DSP -> DSP Wins -> __timestamp
|
|
63
|
-
#IF Only HVR Or DSP -> Particluar wins
|
|
64
|
-
table = spark.read.table(f"{dbName}.{tblName}")
|
|
65
|
-
existing_cols = table.columns
|
|
66
|
-
|
|
67
|
-
# Determine the best column to order by
|
|
68
|
-
order_cols = [c for c in ["src_commit_time", "__timestamp"] if c in existing_cols]
|
|
69
|
-
|
|
70
|
-
if order_cols:
|
|
71
|
-
keyCols = (table
|
|
72
|
-
.orderBy(*order_cols, ascending=False)
|
|
73
|
-
.select("src_key_cols")
|
|
74
|
-
.limit(1)
|
|
75
|
-
.collect()[0][0]
|
|
76
|
-
)
|
|
77
|
-
else:
|
|
78
|
-
keyCols = (table
|
|
56
|
+
keyCols = (spark.read.table(dbName + "." + tblName)
|
|
79
57
|
.select("src_key_cols")
|
|
80
58
|
.limit(1)
|
|
81
59
|
.collect()[0][0]
|
|
82
60
|
)
|
|
83
61
|
return keyCols
|
|
62
|
+
|
|
63
|
+
|
|
84
64
|
except Exception:
|
|
85
65
|
raise Exception(
|
|
86
66
|
f"the column src_key_cols is not present in the given table {dbName}.{tblName}")
|
|
@@ -530,49 +510,4 @@ def buildJoinCondition(keyColsList):
|
|
|
530
510
|
for column in keyColsList:
|
|
531
511
|
condition = condition + "t.`" + column + "` <=> " + "s.`" + column + "` AND "
|
|
532
512
|
|
|
533
|
-
return condition[:-5]
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
# A Function for moving files from DSP to Bronze for the given source table.
|
|
537
|
-
# Since, DSP Writes into two Folders "initial" and "delta", .parquet files from these two folders are recursively
|
|
538
|
-
# moved into Bronze Table Location.
|
|
539
|
-
def move_dsp_to_bronze(srcDatabaseName, srcTableName, src_dsp_path, src_table_path):
|
|
540
|
-
dsp_path = src_dsp_path
|
|
541
|
-
bronze_path = src_table_path
|
|
542
|
-
num_files = 0
|
|
543
|
-
|
|
544
|
-
print(f"Recursively copying all files from {dsp_path} to {bronze_path} (flattened, no hierarchy, source not deleted)")
|
|
545
|
-
|
|
546
|
-
def list_all_files(path):
|
|
547
|
-
files = []
|
|
548
|
-
for item in dbutils.fs.ls(path):
|
|
549
|
-
if item.isDir():
|
|
550
|
-
files.extend(list_all_files(item.path))
|
|
551
|
-
else:
|
|
552
|
-
files.append(item.path)
|
|
553
|
-
return files
|
|
554
|
-
|
|
555
|
-
try:
|
|
556
|
-
all_files = list_all_files(dsp_path)
|
|
557
|
-
for src_file in all_files:
|
|
558
|
-
file_name = src_file.split("/")[-1]
|
|
559
|
-
if ".sap." in file_name:
|
|
560
|
-
dest_file = f"{bronze_path}/{file_name}"
|
|
561
|
-
dbutils.fs.cp(src_file, dest_file)
|
|
562
|
-
#num_files += 1
|
|
563
|
-
else:
|
|
564
|
-
dest_file = f"{bronze_path}/{file_name}"
|
|
565
|
-
dbutils.fs.mv(src_file, dest_file)
|
|
566
|
-
num_files += 1
|
|
567
|
-
except Exception as e:
|
|
568
|
-
print(f"Failed to copy files: {e}")
|
|
569
|
-
|
|
570
|
-
if num_files > 0:
|
|
571
|
-
print(f"Copied {num_files} files from {dsp_path} to {bronze_path}, refreshing table {srcDatabaseName}.{srcTableName}")
|
|
572
|
-
spark.sql(f"REFRESH TABLE {srcDatabaseName}.{srcTableName}")
|
|
573
|
-
print(f"Table {srcDatabaseName}.{srcTableName} is Refreshed")
|
|
574
|
-
else:
|
|
575
|
-
print(f"No files were copied from {dsp_path} to {bronze_path}, so skipping refresh of {srcDatabaseName}.{srcTableName}")
|
|
576
|
-
|
|
577
|
-
# spark.sql(f"REFRESH TABLE {srcDatabaseName}.{srcTableName}")
|
|
578
|
-
# print(f"Table {srcDatabaseName}.{srcTableName} is Refreshed")
|
|
513
|
+
return condition[:-5]
|
{silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/com/phida/main/SilverMerge.py
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from datetime import date, timedelta
|
|
2
2
|
from com.phida.main.sparksession import spark, logger
|
|
3
|
-
from com.phida.main.Operations import describe_table_to_schema,
|
|
3
|
+
from com.phida.main.Operations import describe_table_to_schema, tableExists, addDerivedColumns, createDeltaTable, alterDeltaTable, \
|
|
4
4
|
dropColumns, getDerivedColumnsList, schemaDiff, getKeyCols, buildJoinCondition, buildColumnsDict, hiveDDL, schemaDataTypeDiff, hasColumn
|
|
5
5
|
from com.phida.main.utils import pathExists, convertStrToList
|
|
6
6
|
from pyspark.sql.functions import row_number, col, broadcast,expr, max as spark_max, lit, when, coalesce
|
|
@@ -28,11 +28,8 @@ class SilverMerge:
|
|
|
28
28
|
cluster_table_path: String - Path to the cluster table
|
|
29
29
|
enable_delete_filter: String - Flag to enable/disable filtering of deleted records (default: 'N')
|
|
30
30
|
use_auto_loader: String - Flag to enable/disable use of autoloader for reading source table (default: 'N')
|
|
31
|
-
is_dsp_kernel: String - Flag to indicate if the kernel is a DSP kernel, which requires file movement from DSP to Bronze (default: 'N')
|
|
32
|
-
src_dsp_path: String - The DSP path to read from if it's a DSP kernel (optional, only needed if is_dsp_kernel is 'Y')
|
|
33
31
|
|
|
34
32
|
methods:
|
|
35
|
-
move_dsp_to_bronze
|
|
36
33
|
silverCleansing
|
|
37
34
|
prepareTarget
|
|
38
35
|
upsertToDelta
|
|
@@ -42,12 +39,12 @@ class SilverMerge:
|
|
|
42
39
|
from com.phida.SilverMerge import SilverMerge
|
|
43
40
|
silverMergeObj = SilverMerge(srcDatabaseName, srcTableName, tgtDatabaseName, tgtTableName,
|
|
44
41
|
tgtCheckpoint, tgtTablePath, tgtPartitionColumns, derivedColExpr,
|
|
45
|
-
triggerOnce, dropColumnStr, pruneColumn, cluster_table_path, enable_delete_filter, use_auto_loader
|
|
42
|
+
triggerOnce, dropColumnStr, pruneColumn, cluster_table_path, enable_delete_filter, use_auto_loader)
|
|
46
43
|
|
|
47
44
|
"""
|
|
48
45
|
def __init__(self, srcDatabaseName, srcTableName, tgtDatabaseName, tgtTableName,
|
|
49
46
|
tgtCheckpoint, tgtTablePath, tgtPartitionColumns, derivedColExpr,
|
|
50
|
-
triggerOnce, dropColumnStr, pruneColumn, cluster_table_path, enable_delete_filter, use_auto_loader, modified_after=None, backfill_interval=None
|
|
47
|
+
triggerOnce, dropColumnStr, pruneColumn, cluster_table_path, enable_delete_filter, use_auto_loader, modified_after=None, backfill_interval=None):
|
|
51
48
|
"""
|
|
52
49
|
desc:
|
|
53
50
|
Initialize the required class variables
|
|
@@ -67,8 +64,6 @@ class SilverMerge:
|
|
|
67
64
|
cluster_table_path: String - Path to the cluster table
|
|
68
65
|
enable_delete_filter: String - Flag to enable/disable filtering of deleted records (default: 'N')
|
|
69
66
|
use_auto_loader: String - Flag to enable/disable use of autoloader for reading source table (default: 'N')
|
|
70
|
-
is_dsp_kernel: String - Flag to indicate if the kernel is a DSP kernel, which requires file movement from DSP to Bronze (default: 'N')
|
|
71
|
-
src_dsp_path: String - The DSP path to read from if it's a DSP kernel (optional, only needed if is_dsp_kernel is 'Y')
|
|
72
67
|
"""
|
|
73
68
|
|
|
74
69
|
logger.info("phida_log: Initialising class variables")
|
|
@@ -90,16 +85,7 @@ class SilverMerge:
|
|
|
90
85
|
self.enable_delete_filter = enable_delete_filter.strip().upper() if enable_delete_filter else 'N'
|
|
91
86
|
self.use_auto_loader = use_auto_loader.strip().upper() if use_auto_loader and use_auto_loader.strip().upper() in ('Y') else 'N'
|
|
92
87
|
self.modified_after = modified_after.strip() if modified_after else (date.today() - timedelta(days=15)).strftime('%Y-%m-%d')
|
|
93
|
-
self.backfill_interval = backfill_interval if backfill_interval else "1
|
|
94
|
-
self.is_dsp_kernel = is_dsp_kernel.strip().upper() if is_dsp_kernel else 'N' #To determine if Kernel is loaded via Datasphere
|
|
95
|
-
self.src_dsp_path = src_dsp_path if src_dsp_path else None
|
|
96
|
-
|
|
97
|
-
#Run file movement between DSP and Bronze only if it's a DSP kernel, to ensure we don't have unnecessary file movements for non-DSP kernels
|
|
98
|
-
if self.is_dsp_kernel == 'Y':
|
|
99
|
-
src_table_path = spark.sql(f"DESCRIBE DETAIL {self.srcDatabaseName}.{self.srcTableName}").collect()[0]['location']
|
|
100
|
-
logger.info(f"phida_log: File movement between DSP and Bronze")
|
|
101
|
-
print(f"[SilverMerge] File movement between DSP and Bronze")
|
|
102
|
-
move_dsp_to_bronze(self.srcDatabaseName ,self.srcTableName, self.src_dsp_path, src_table_path)
|
|
88
|
+
self.backfill_interval = backfill_interval if backfill_interval else "1 week"
|
|
103
89
|
|
|
104
90
|
logger.info(f"phida_log: Check if source table {self.srcDatabaseName}.{self.srcTableName} exists")
|
|
105
91
|
|
|
@@ -204,8 +190,10 @@ class SilverMerge:
|
|
|
204
190
|
|
|
205
191
|
silverDerivedColumns = silverDerivedColumns.drop("__timestamp")
|
|
206
192
|
logger.info("phida_log: Mapped DSP __timestamp to src_commit_time")
|
|
193
|
+
print("[SilverMerge] Mapped DSP __timestamp to src_commit_time")
|
|
207
194
|
else:
|
|
208
195
|
logger.info("phida_log: HVR data; src_commit_time already present")
|
|
196
|
+
print("[SilverMerge] HVR data; src_commit_time already present")
|
|
209
197
|
|
|
210
198
|
# Convert all column names to lower case to ensure
|
|
211
199
|
# the target Delta table is created and maintained with lower-case column names.
|
|
@@ -404,31 +392,41 @@ class SilverMerge:
|
|
|
404
392
|
microBatchOutputDF = hvr_preprocessed_df.unionByName(dsp_df, allowMissingColumns=True)
|
|
405
393
|
|
|
406
394
|
# Convert all column names to lower case just before writing to Silver
|
|
407
|
-
lower_cols = [c.lower() for c in microBatchOutputDF.columns]
|
|
408
|
-
microBatchOutputDF = microBatchOutputDF.toDF(*lower_cols)
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
#
|
|
412
|
-
#
|
|
413
|
-
#
|
|
395
|
+
#lower_cols = [c.lower() for c in microBatchOutputDF.columns]
|
|
396
|
+
#microBatchOutputDF = microBatchOutputDF.toDF(*lower_cols)
|
|
397
|
+
"Commenting above column lowering as it is already done in silverCleansing() method"
|
|
398
|
+
|
|
399
|
+
# Compatible ordering across all modes.
|
|
400
|
+
# Do not infer mode from column presence because unionByName(allowMissingColumns=True)
|
|
401
|
+
# can materialize placeholder columns with null values.
|
|
402
|
+
# Example: HVR-only batch → after union, __operation_type column exists but is all NULL.
|
|
403
|
+
# Checking column presence alone would incorrectly route HVR data to mixed-mode ordering.
|
|
414
404
|
batch_cols = set(microBatchOutputDF.columns)
|
|
415
|
-
has_hvr_key = "hvr_integ_key" in batch_cols
|
|
416
|
-
has_dsp_op = "__operation_type" in batch_cols
|
|
405
|
+
has_hvr_key = "hvr_integ_key" in batch_cols # True for HVR and mixed tables
|
|
406
|
+
has_dsp_op = "__operation_type" in batch_cols # True for DSP and mixed tables (may be all-null after union)
|
|
407
|
+
has_src_commit_time = "src_commit_time" in batch_cols # Common timestamp column for both sources
|
|
417
408
|
|
|
418
409
|
if has_hvr_key and not has_dsp_op:
|
|
419
|
-
# HVR-only:
|
|
410
|
+
# HVR-only table (no DSP column at all): deduplicate by integ_key descending — highest key = latest change.
|
|
420
411
|
windowSpec = Window.partitionBy(self.keyColsList).orderBy(col("hvr_integ_key").desc())
|
|
421
|
-
elif has_hvr_key and has_dsp_op:
|
|
422
|
-
# Mixed mode: prioritize DSP records, then newest timestamp
|
|
423
|
-
is_dsp_record = col("hvr_integ_key").isNull()
|
|
424
|
-
windowSpec = Window.partitionBy(self.keyColsList).orderBy(
|
|
425
|
-
is_dsp_record.desc(),
|
|
426
|
-
col("src_commit_time").desc(), #__timestamp is casted to src_commit_time in silverCleansing()
|
|
427
|
-
col("hvr_integ_key").desc()
|
|
428
|
-
)
|
|
429
412
|
else:
|
|
430
|
-
#
|
|
431
|
-
|
|
413
|
+
# Mixed or DSP path: build ordering dynamically based on which recency columns actually exist.
|
|
414
|
+
order_exprs = []
|
|
415
|
+
if has_dsp_op:
|
|
416
|
+
# Flag actual DSP rows (op in A/I/L/X = 1) vs HVR rows or union-placeholder nulls (= 0).
|
|
417
|
+
# DSP rows sort first (desc), so DSP always wins over HVR for the same key in a mixed batch.
|
|
418
|
+
is_dsp_record = when(col("__operation_type").isin("A", "I", "L", "X"), lit(1)).otherwise(lit(0))
|
|
419
|
+
order_exprs.append(is_dsp_record.desc())
|
|
420
|
+
if has_src_commit_time:
|
|
421
|
+
# Within the same source type, pick the most recent record by commit timestamp.
|
|
422
|
+
order_exprs.append(col("src_commit_time").desc_nulls_last())
|
|
423
|
+
if has_hvr_key:
|
|
424
|
+
# Final tiebreaker for HVR rows: higher integ_key = later change from source.
|
|
425
|
+
order_exprs.append(col("hvr_integ_key").desc_nulls_last())
|
|
426
|
+
if not order_exprs:
|
|
427
|
+
# Defensive fallback: no recency column available, treat all rows as equal.
|
|
428
|
+
order_exprs.append(lit(1))
|
|
429
|
+
windowSpec = Window.partitionBy(self.keyColsList).orderBy(*order_exprs)
|
|
432
430
|
|
|
433
431
|
microBatchOutputDF = microBatchOutputDF.withColumn("latest_record", row_number().over(windowSpec)).filter(
|
|
434
432
|
"latest_record == 1").drop("latest_record")
|
|
@@ -436,24 +434,60 @@ class SilverMerge:
|
|
|
436
434
|
if self.enable_delete_filter == 'Y':
|
|
437
435
|
microBatchOutputDF = self.filter_deleted_records(microBatchOutputDF)
|
|
438
436
|
|
|
439
|
-
#
|
|
440
|
-
# Referencing s.__operation_type when the source is HVR-only causes DELTA_MERGE_UNRESOLVED_EXPRESSION.
|
|
437
|
+
# Build delete/update conditions only from operation columns present in the batch to avoid UNRESOLVED_EXPRESSION errors.
|
|
441
438
|
delete_parts = []
|
|
439
|
+
update_insert_parts = []
|
|
440
|
+
|
|
441
|
+
# HVR: source_operation 0=delete, 3=before-image; all others are insert/update.
|
|
442
442
|
if has_source_operation:
|
|
443
|
-
delete_parts.append(
|
|
443
|
+
delete_parts.append(
|
|
444
|
+
"(s.source_operation IS NOT NULL AND s.source_operation in (0,3))"
|
|
445
|
+
)
|
|
446
|
+
update_insert_parts.append(
|
|
447
|
+
"(s.source_operation IS NOT NULL AND s.source_operation not in (0,3))"
|
|
448
|
+
)
|
|
449
|
+
|
|
450
|
+
# DSP: __operation_type X=delete; A/I/L are insert/update variants.
|
|
444
451
|
if has_operation_type:
|
|
445
|
-
delete_parts.append(
|
|
452
|
+
delete_parts.append(
|
|
453
|
+
"(s.__operation_type IS NOT NULL AND s.__operation_type in ('X'))"
|
|
454
|
+
)
|
|
455
|
+
update_insert_parts.append(
|
|
456
|
+
"(s.__operation_type IS NOT NULL AND s.__operation_type in ('A','I','L'))"
|
|
457
|
+
)
|
|
446
458
|
|
|
447
|
-
|
|
459
|
+
# At least one operation column must exist; otherwise the batch is malformed.
|
|
460
|
+
if not delete_parts or not update_insert_parts:
|
|
448
461
|
raise Exception("No operation column found in source batch")
|
|
449
462
|
|
|
450
|
-
|
|
451
|
-
|
|
463
|
+
# OR joins HVR and DSP branches because a row belongs to exactly one source system.
|
|
464
|
+
delete_condition = " OR ".join(delete_parts)
|
|
465
|
+
update_insert_condition = " OR ".join(update_insert_parts)
|
|
466
|
+
|
|
467
|
+
# Freshness guard: prevent a late/older microbatch from overwriting a newer target row.
|
|
468
|
+
# src_commit_time is the common recency column populated for both HVR and DSP flows.
|
|
469
|
+
# Example:
|
|
470
|
+
# Batch 1 (arrives first): src_commit_time = '2024-01-01 10:00' → written to Silver (t.src_commit_time = '2024-01-01 10:00')
|
|
471
|
+
# Batch 2 (arrives late): src_commit_time = '2024-01-01 08:00' → BLOCKED because s.src_commit_time < t.src_commit_time
|
|
472
|
+
# Batch 3 (arrives later): src_commit_time = '2024-01-01 12:00' → ALLOWED because s.src_commit_time >= t.src_commit_time
|
|
473
|
+
# New key (no target row): t.src_commit_time IS NULL → ALLOWED (first-time insert)
|
|
474
|
+
freshness_condition = """
|
|
475
|
+
(
|
|
476
|
+
t.src_commit_time IS NULL
|
|
477
|
+
OR (s.src_commit_time IS NOT NULL AND s.src_commit_time >= t.src_commit_time)
|
|
478
|
+
)
|
|
479
|
+
"""
|
|
480
|
+
|
|
481
|
+
# Apply freshness to matched delete so stale deletes cannot remove newer target rows.
|
|
482
|
+
matched_delete_condition = f"({delete_condition}) AND ({freshness_condition})"
|
|
483
|
+
|
|
484
|
+
# Apply freshness to matched update so older records do not overwrite newer silver state.
|
|
485
|
+
matched_update_condition = f"({update_insert_condition}) AND ({freshness_condition})"
|
|
452
486
|
|
|
453
487
|
print(f"[SilverMerge] Executing merge for batch {batchId} into {self.tgtDatabaseName}.{self.tgtTableName}...")
|
|
454
488
|
tgtDeltaTable.alias("t").merge(microBatchOutputDF.alias("s"), self.condition) \
|
|
455
|
-
.whenMatchedDelete(
|
|
456
|
-
.whenMatchedUpdate(condition=
|
|
489
|
+
.whenMatchedDelete(matched_delete_condition) \
|
|
490
|
+
.whenMatchedUpdate(condition=matched_update_condition, set=self.columnsDict) \
|
|
457
491
|
.whenNotMatchedInsert(condition=update_insert_condition, values=self.columnsDict) \
|
|
458
492
|
.execute()
|
|
459
493
|
print(f"[SilverMerge] Merge for batch {batchId} complete.")
|
{silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/com/phida/main/Maintenance.py
RENAMED
|
File without changes
|
|
File without changes
|
{silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/com/phida/main/PerfAnalyzer.py
RENAMED
|
File without changes
|
{silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/com/phida/main/WorkflowBuilder.py
RENAMED
|
File without changes
|
{silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/com/phida/main/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/com/phida/main/sparksession.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/com/phida/tests/OperationsTest.py
RENAMED
|
File without changes
|
{silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/com/phida/tests/__init__.py
RENAMED
|
File without changes
|
{silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/com/phida/tests/main_test.py
RENAMED
|
File without changes
|
{silverstreamingapplication-1.7 → silverstreamingapplication-1.9}/com/phida/tests/utils_test.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|