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.
Files changed (22) hide show
  1. {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/PKG-INFO +1 -1
  2. {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/main/Operations.py +4 -69
  3. {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/main/SilverMerge.py +10 -21
  4. {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/main/WorkflowBuilder.py +3 -13
  5. {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/setup.py +1 -1
  6. {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/silverstreamingapplication.egg-info/PKG-INFO +1 -1
  7. {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/main/Maintenance.py +0 -0
  8. {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/main/PartitionAnalyzer.py +0 -0
  9. {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/main/PerfAnalyzer.py +0 -0
  10. {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/main/__init__.py +0 -0
  11. {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/main/logging.py +0 -0
  12. {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/main/sparksession.py +0 -0
  13. {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/main/utils.py +0 -0
  14. {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/main/utilsDatabricksAPI.py +0 -0
  15. {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/tests/OperationsTest.py +0 -0
  16. {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/tests/__init__.py +0 -0
  17. {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/tests/main_test.py +0 -0
  18. {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/com/phida/tests/utils_test.py +0 -0
  19. {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/setup.cfg +0 -0
  20. {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/silverstreamingapplication.egg-info/SOURCES.txt +0 -0
  21. {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/silverstreamingapplication.egg-info/dependency_links.txt +0 -0
  22. {silverstreamingapplication-1.8 → silverstreamingapplication-1.9}/silverstreamingapplication.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: silverstreamingapplication
3
- Version: 1.8
3
+ Version: 1.9
4
4
  Summary: initial version
5
5
  Home-page:
6
6
  Author:
@@ -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
- # To accomodate both the hvr and dsp data together and seperately
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]
@@ -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, move_dsp_to_bronze, tableExists, addDerivedColumns, createDeltaTable, alterDeltaTable, \
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, is_dsp_kernel, src_dsp_path)
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, is_dsp_kernel='N', src_dsp_path=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 month"
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").desc_nulls_last())
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 = []
@@ -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, is_dsp_kernel, src_dsp_path, library):
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, is_dsp_kernel, src_dsp_path, self.library)
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:
@@ -2,7 +2,7 @@ from setuptools import setup
2
2
 
3
3
  setup(
4
4
  name='silverstreamingapplication',
5
- version='1.8',
5
+ version='1.9',
6
6
  packages=['com.phida.main', 'com.phida.tests'],
7
7
  url='',
8
8
  license='',
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: silverstreamingapplication
3
- Version: 1.8
3
+ Version: 1.9
4
4
  Summary: initial version
5
5
  Home-page:
6
6
  Author: