SilverStreamingApplication 1.8__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.8 → silverstreamingapplication-1.9}/PKG-INFO +1 -1
- {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/main/Operations.py +4 -69
- {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/main/SilverMerge.py +10 -21
- {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/main/WorkflowBuilder.py +3 -13
- {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/setup.py +1 -1
- {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/silverstreamingapplication.egg-info/PKG-INFO +1 -1
- {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/main/Maintenance.py +0 -0
- {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/main/PartitionAnalyzer.py +0 -0
- {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/main/PerfAnalyzer.py +0 -0
- {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/main/__init__.py +0 -0
- {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/main/logging.py +0 -0
- {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/main/sparksession.py +0 -0
- {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/main/utils.py +0 -0
- {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/main/utilsDatabricksAPI.py +0 -0
- {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/tests/OperationsTest.py +0 -0
- {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/tests/__init__.py +0 -0
- {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/tests/main_test.py +0 -0
- {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/tests/utils_test.py +0 -0
- {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/setup.cfg +0 -0
- {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/silverstreamingapplication.egg-info/SOURCES.txt +0 -0
- {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/silverstreamingapplication.egg-info/dependency_links.txt +0 -0
- {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/silverstreamingapplication.egg-info/top_level.txt +0 -0
{silverstreamingapplication-1.8 → 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.8 → 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,8 +392,9 @@ 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)
|
|
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"
|
|
409
398
|
|
|
410
399
|
# Compatible ordering across all modes.
|
|
411
400
|
# Do not infer mode from column presence because unionByName(allowMissingColumns=True)
|
|
@@ -419,7 +408,7 @@ class SilverMerge:
|
|
|
419
408
|
|
|
420
409
|
if has_hvr_key and not has_dsp_op:
|
|
421
410
|
# HVR-only table (no DSP column at all): deduplicate by integ_key descending — highest key = latest change.
|
|
422
|
-
windowSpec = Window.partitionBy(self.keyColsList).orderBy(col("hvr_integ_key").
|
|
411
|
+
windowSpec = Window.partitionBy(self.keyColsList).orderBy(col("hvr_integ_key").desc())
|
|
423
412
|
else:
|
|
424
413
|
# Mixed or DSP path: build ordering dynamically based on which recency columns actually exist.
|
|
425
414
|
order_exprs = []
|
{silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/main/WorkflowBuilder.py
RENAMED
|
@@ -72,7 +72,7 @@ class WorkflowBuilder:
|
|
|
72
72
|
@staticmethod
|
|
73
73
|
def createTask(taskKey, jobClusterKey, notebookPath, srcDatabaseName, srcTableName, tgtDatabaseName, tgtTableName,
|
|
74
74
|
tgtCheckpoint, tgtTablePath, tgtPartitionColumns, derivedColExpr, triggerOnce, dropColumnStr,
|
|
75
|
-
pruneColumn, cluster_table_path, enable_delete_filter, enable_autoloader, modified_after, backfill_interval,
|
|
75
|
+
pruneColumn, cluster_table_path, enable_delete_filter, enable_autoloader, modified_after, backfill_interval, library):
|
|
76
76
|
"""
|
|
77
77
|
desc:
|
|
78
78
|
A method for creating the dict/json for a single task
|
|
@@ -141,9 +141,7 @@ class WorkflowBuilder:
|
|
|
141
141
|
"enable_delete_filter": str(enable_delete_filter),
|
|
142
142
|
"enable_autoloader": enable_autoloader,
|
|
143
143
|
"modified_after": modified_after,
|
|
144
|
-
"backfill_interval": backfill_interval
|
|
145
|
-
"is_dsp_kernel": is_dsp_kernel,
|
|
146
|
-
"src_dsp_path": src_dsp_path
|
|
144
|
+
"backfill_interval": backfill_interval
|
|
147
145
|
}
|
|
148
146
|
},
|
|
149
147
|
"timeout_seconds": timeout_seconds,
|
|
@@ -362,19 +360,11 @@ class WorkflowBuilder:
|
|
|
362
360
|
backfill_interval = task['backfill_interval']
|
|
363
361
|
except:
|
|
364
362
|
backfill_interval = ""
|
|
365
|
-
try:
|
|
366
|
-
is_dsp_kernel = task['is_dsp_kernel']
|
|
367
|
-
except:
|
|
368
|
-
is_dsp_kernel = ""
|
|
369
|
-
try:
|
|
370
|
-
src_dsp_path = task['src_dsp_path']
|
|
371
|
-
except:
|
|
372
|
-
src_dsp_path = ""
|
|
373
363
|
|
|
374
364
|
taskTemp = self.createTask(taskKey, jobClusterKey, notebookPath, srcDatabaseName, srcTableName,
|
|
375
365
|
tgtDatabaseName, tgtTableName, tgtCheckpoint, tgtTablePath,
|
|
376
366
|
tgtPartitionColumns, derivedColExpr, triggerOnce, dropColumnStr,
|
|
377
|
-
pruneColumn, cluster_table_path, enable_delete_filter, enable_autoloader, modified_after, backfill_interval,
|
|
367
|
+
pruneColumn, cluster_table_path, enable_delete_filter, enable_autoloader, modified_after, backfill_interval, self.library)
|
|
378
368
|
|
|
379
369
|
tasks.append(taskTemp)
|
|
380
370
|
if jobId is None:
|
{silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/main/Maintenance.py
RENAMED
|
File without changes
|
|
File without changes
|
{silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/main/PerfAnalyzer.py
RENAMED
|
File without changes
|
{silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/main/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/main/sparksession.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/tests/OperationsTest.py
RENAMED
|
File without changes
|
{silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/tests/__init__.py
RENAMED
|
File without changes
|
{silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/tests/main_test.py
RENAMED
|
File without changes
|
{silverstreamingapplication-1.8 → 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
|