splink 4.0.12.dev1__tar.gz → 4.0.14__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 (165) hide show
  1. {splink-4.0.12.dev1 → splink-4.0.14}/PKG-INFO +3 -1
  2. {splink-4.0.12.dev1 → splink-4.0.14}/README.md +2 -0
  3. {splink-4.0.12.dev1 → splink-4.0.14}/pyproject.toml +7 -1
  4. {splink-4.0.12.dev1 → splink-4.0.14}/splink/__init__.py +1 -1
  5. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/blocking.py +63 -28
  6. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/connected_components.py +1 -1
  7. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/input_column.py +7 -4
  8. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/spark/database_api.py +1 -0
  9. {splink-4.0.12.dev1 → splink-4.0.14}/.gitignore +0 -0
  10. {splink-4.0.12.dev1 → splink-4.0.14}/LICENSE +0 -0
  11. {splink-4.0.12.dev1 → splink-4.0.14}/splink/backends/athena.py +0 -0
  12. {splink-4.0.12.dev1 → splink-4.0.14}/splink/backends/duckdb.py +0 -0
  13. {splink-4.0.12.dev1 → splink-4.0.14}/splink/backends/postgres.py +0 -0
  14. {splink-4.0.12.dev1 → splink-4.0.14}/splink/backends/spark.py +0 -0
  15. {splink-4.0.12.dev1 → splink-4.0.14}/splink/backends/sqlite.py +0 -0
  16. {splink-4.0.12.dev1 → splink-4.0.14}/splink/blocking_analysis.py +0 -0
  17. {splink-4.0.12.dev1 → splink-4.0.14}/splink/blocking_rule_library.py +0 -0
  18. {splink-4.0.12.dev1 → splink-4.0.14}/splink/clustering.py +0 -0
  19. {splink-4.0.12.dev1 → splink-4.0.14}/splink/comparison_level_library.py +0 -0
  20. {splink-4.0.12.dev1 → splink-4.0.14}/splink/comparison_library.py +0 -0
  21. {splink-4.0.12.dev1 → splink-4.0.14}/splink/datasets.py +0 -0
  22. {splink-4.0.12.dev1 → splink-4.0.14}/splink/exploratory.py +0 -0
  23. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/__init__.py +0 -0
  24. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/accuracy.py +0 -0
  25. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/athena/__init__.py +0 -0
  26. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/athena/athena_helpers/__init__.py +0 -0
  27. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/athena/athena_helpers/athena_transforms.py +0 -0
  28. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/athena/athena_helpers/athena_utils.py +0 -0
  29. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/athena/database_api.py +0 -0
  30. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/athena/dataframe.py +0 -0
  31. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/block_from_labels.py +0 -0
  32. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/blocking_analysis.py +0 -0
  33. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/blocking_rule_creator.py +0 -0
  34. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/blocking_rule_creator_utils.py +0 -0
  35. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/blocking_rule_library.py +0 -0
  36. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/cache_dict_with_logging.py +0 -0
  37. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/charts.py +0 -0
  38. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/cluster_studio.py +0 -0
  39. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/clustering.py +0 -0
  40. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/column_expression.py +0 -0
  41. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/comparison.py +0 -0
  42. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/comparison_creator.py +0 -0
  43. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/comparison_level.py +0 -0
  44. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/comparison_level_composition.py +0 -0
  45. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/comparison_level_creator.py +0 -0
  46. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/comparison_level_library.py +0 -0
  47. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/comparison_level_sql.py +0 -0
  48. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/comparison_library.py +0 -0
  49. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/comparison_vector_distribution.py +0 -0
  50. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/comparison_vector_values.py +0 -0
  51. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/completeness.py +0 -0
  52. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/constants.py +0 -0
  53. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/cost_of_blocking_rules.py +0 -0
  54. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/database_api.py +0 -0
  55. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/databricks/__init__.py +0 -0
  56. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/databricks/enable_splink.py +0 -0
  57. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/datasets/__init__.py +0 -0
  58. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/datasets/metadata.py +0 -0
  59. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/datasets/splink_datasets.py +0 -0
  60. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/datasets/utils.py +0 -0
  61. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/default_from_jsonschema.py +0 -0
  62. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/dialects.py +0 -0
  63. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/duckdb/__init__.py +0 -0
  64. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/duckdb/database_api.py +0 -0
  65. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/duckdb/dataframe.py +0 -0
  66. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/duckdb/duckdb_helpers/__init__.py +0 -0
  67. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/duckdb/duckdb_helpers/duckdb_helpers.py +0 -0
  68. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/edge_metrics.py +0 -0
  69. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/em_training_session.py +0 -0
  70. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/estimate_u.py +0 -0
  71. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/exceptions.py +0 -0
  72. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/expectation_maximisation.py +0 -0
  73. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/DEPENDENCY_LICENSES.txt +0 -0
  74. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/chart_defs/accuracy_chart.json +0 -0
  75. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/chart_defs/blocking_rule_generated_comparisons.json +0 -0
  76. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/chart_defs/comparator_score_chart.json +0 -0
  77. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/chart_defs/comparator_score_threshold_chart.json +0 -0
  78. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/chart_defs/completeness.json +0 -0
  79. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/chart_defs/m_u_parameters_interactive_history.json +0 -0
  80. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/chart_defs/match_weight_histogram.json +0 -0
  81. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/chart_defs/match_weights_interactive_history.json +0 -0
  82. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/chart_defs/match_weights_waterfall.json +0 -0
  83. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/chart_defs/missingness.json +0 -0
  84. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/chart_defs/parameter_estimate_comparisons.json +0 -0
  85. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/chart_defs/phonetic_match_chart.json +0 -0
  86. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/chart_defs/precision_recall.json +0 -0
  87. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/chart_defs/probability_two_random_records_match_iteration.json +0 -0
  88. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/chart_defs/profile_data.json +0 -0
  89. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/chart_defs/roc.json +0 -0
  90. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/chart_defs/tf_adjustment_chart.json +0 -0
  91. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/chart_defs/threshold_selection_tool.json +0 -0
  92. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/chart_defs/unlinkables_chart_def.json +0 -0
  93. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/external_js/d3@7.8.5 +0 -0
  94. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/external_js/stdlib.js@5.8.3 +0 -0
  95. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/external_js/vega-embed@6.20.2 +0 -0
  96. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/external_js/vega-lite@5.2.0 +0 -0
  97. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/external_js/vega@5.31.0 +0 -0
  98. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/labelling_tool/slt.js +0 -0
  99. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/labelling_tool/template.j2 +0 -0
  100. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/settings_jsonschema.json +0 -0
  101. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/spark_jars/scala-udf-similarity-0.1.2_spark3.x.jar +0 -0
  102. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/spark_jars/scala-udf-similarity-0.2.0_spark4.x.jar +0 -0
  103. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/splink_cluster_studio/cluster_template.j2 +0 -0
  104. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/splink_cluster_studio/custom.css +0 -0
  105. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/splink_comparison_viewer/custom.css +0 -0
  106. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/splink_comparison_viewer/template.j2 +0 -0
  107. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/splink_vis_utils/splink_vis_utils.js +0 -0
  108. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/files/templates/single_chart_template.html +0 -0
  109. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/find_brs_with_comparison_counts_below_threshold.py +0 -0
  110. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/find_matches_to_new_records.py +0 -0
  111. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/graph_metrics.py +0 -0
  112. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/labelling_tool.py +0 -0
  113. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/linker.py +0 -0
  114. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/linker_components/__init__.py +0 -0
  115. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/linker_components/clustering.py +0 -0
  116. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/linker_components/evaluation.py +0 -0
  117. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/linker_components/inference.py +0 -0
  118. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/linker_components/misc.py +0 -0
  119. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/linker_components/table_management.py +0 -0
  120. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/linker_components/training.py +0 -0
  121. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/linker_components/visualisations.py +0 -0
  122. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/logging_messages.py +0 -0
  123. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/lower_id_on_lhs.py +0 -0
  124. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/m_from_labels.py +0 -0
  125. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/m_training.py +0 -0
  126. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/m_u_records_to_parameters.py +0 -0
  127. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/match_weights_histogram.py +0 -0
  128. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/misc.py +0 -0
  129. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/one_to_one_clustering.py +0 -0
  130. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/optimise_cost_of_brs.py +0 -0
  131. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/parse_sql.py +0 -0
  132. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/pipeline.py +0 -0
  133. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/postgres/__init__.py +0 -0
  134. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/postgres/database_api.py +0 -0
  135. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/postgres/dataframe.py +0 -0
  136. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/predict.py +0 -0
  137. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/profile_data.py +0 -0
  138. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/realtime.py +0 -0
  139. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/settings.py +0 -0
  140. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/settings_creator.py +0 -0
  141. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/settings_validation/__init__.py +0 -0
  142. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/settings_validation/log_invalid_columns.py +0 -0
  143. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/settings_validation/settings_column_cleaner.py +0 -0
  144. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/settings_validation/settings_validation_log_strings.py +0 -0
  145. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/settings_validation/valid_types.py +0 -0
  146. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/similarity_analysis.py +0 -0
  147. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/spark/__init__.py +0 -0
  148. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/spark/dataframe.py +0 -0
  149. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/spark/jar_location.py +0 -0
  150. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/spark/spark_helpers/__init__.py +0 -0
  151. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/spark/spark_helpers/custom_spark_dialect.py +0 -0
  152. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/splink_comparison_viewer.py +0 -0
  153. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/splink_dataframe.py +0 -0
  154. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/sql_transform.py +0 -0
  155. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/sqlite/__init__.py +0 -0
  156. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/sqlite/database_api.py +0 -0
  157. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/sqlite/dataframe.py +0 -0
  158. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/term_frequencies.py +0 -0
  159. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/testing.py +0 -0
  160. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/unique_id_concat.py +0 -0
  161. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/unlinkables.py +0 -0
  162. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/validate_jsonschema.py +0 -0
  163. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/vertically_concatenate.py +0 -0
  164. {splink-4.0.12.dev1 → splink-4.0.14}/splink/internals/waterfall_chart.py +0 -0
  165. {splink-4.0.12.dev1 → splink-4.0.14}/splink/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: splink
3
- Version: 4.0.12.dev1
3
+ Version: 4.0.14
4
4
  Summary: Fast probabilistic data linkage at scale
5
5
  Project-URL: Homepage, https://github.com/moj-analytical-services/splink
6
6
  Project-URL: Repository, https://github.com/moj-analytical-services/splink
@@ -201,6 +201,8 @@ To find the best place to ask a question, report a bug or get general advice, pl
201
201
 
202
202
  🥇 Civil Service Awards 2025: Innovation category - [Winner](https://x.com/CSWnews/status/1998488787433979981)
203
203
 
204
+ 🥇 Civil Service Awards 2025: The Excellence In Delivery Award was [won](https://www.civilserviceawards.com/winners-2025/) by a dashboard powered by Splink.
205
+
204
206
  🥇 OpenUK Awards 2025: Open data category - [Winner](https://openuk.uk/awards/)
205
207
 
206
208
  🥈 Civil Service Awards 2023: Best Use of Data, Science, and Technology - [Runner up](https://www.civilserviceawards.com/best-use-of-data-science-and-technology-award-2/)
@@ -172,6 +172,8 @@ To find the best place to ask a question, report a bug or get general advice, pl
172
172
 
173
173
  🥇 Civil Service Awards 2025: Innovation category - [Winner](https://x.com/CSWnews/status/1998488787433979981)
174
174
 
175
+ 🥇 Civil Service Awards 2025: The Excellence In Delivery Award was [won](https://www.civilserviceawards.com/winners-2025/) by a dashboard powered by Splink.
176
+
175
177
  🥇 OpenUK Awards 2025: Open data category - [Winner](https://openuk.uk/awards/)
176
178
 
177
179
  🥈 Civil Service Awards 2023: Best Use of Data, Science, and Technology - [Runner up](https://www.civilserviceawards.com/best-use-of-data-science-and-technology-award-2/)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "splink"
3
- version = "4.0.12.dev1"
3
+ version = "4.0.14"
4
4
  description = "Fast probabilistic data linkage at scale"
5
5
  authors = [
6
6
  { name = "Robin Linacre", email = "robinlinacre@hotmail.com" },
@@ -91,6 +91,12 @@ conflicts = [
91
91
  { extra = "athena" }
92
92
  ]
93
93
  ]
94
+ # problematic constraints, and we do not test or otherwise use this
95
+ # we are removing in Splink 5 anyway
96
+ exclude-dependencies = ["awswrangler"]
97
+
98
+ [tool.uv.dependency-groups]
99
+ docs = { requires-python = ">=3.13" }
94
100
 
95
101
  [build-system]
96
102
  requires = ["hatchling"]
@@ -56,7 +56,7 @@ def __getattr__(name):
56
56
  raise AttributeError(f"module 'splink' has no attribute '{name}'") from None
57
57
 
58
58
 
59
- __version__ = "4.0.12.dev1"
59
+ __version__ = "4.0.14"
60
60
 
61
61
 
62
62
  __all__ = [
@@ -16,7 +16,10 @@ from splink.internals.misc import ensure_is_list
16
16
  from splink.internals.pipeline import CTEPipeline
17
17
  from splink.internals.splink_dataframe import SplinkDataFrame
18
18
  from splink.internals.unique_id_concat import _composite_unique_id_from_nodes_sql
19
- from splink.internals.vertically_concatenate import vertically_concatenate_sql
19
+ from splink.internals.vertically_concatenate import (
20
+ split_df_concat_with_tf_into_two_tables_sqls,
21
+ vertically_concatenate_sql,
22
+ )
20
23
 
21
24
  logger = logging.getLogger(__name__)
22
25
 
@@ -386,6 +389,8 @@ class ExplodingBlockingRule(BlockingRule):
386
389
  unique_id_input_column: InputColumn,
387
390
  br: BlockingRule,
388
391
  link_type: "LinkTypeLiteralType",
392
+ input_tablename_l: str,
393
+ input_tablename_r: str,
389
394
  ) -> str:
390
395
  """generates a table of the marginal id pairs from the exploded blocking rule
391
396
  i.e. pairs are only created that match this blocking rule and NOT any of
@@ -402,11 +407,6 @@ class ExplodingBlockingRule(BlockingRule):
402
407
  id_expr_l = _composite_unique_id_from_nodes_sql(unique_id_input_columns, "l")
403
408
  id_expr_r = _composite_unique_id_from_nodes_sql(unique_id_input_columns, "r")
404
409
 
405
- if link_type == "two_dataset_link_only":
406
- where_condition = (
407
- where_condition + " and l.source_dataset < r.source_dataset"
408
- )
409
-
410
410
  exclude_sql = self.exclude_pairs_generated_by_all_preceding_rules_sql(
411
411
  source_dataset_input_column, unique_id_input_column
412
412
  )
@@ -414,8 +414,8 @@ class ExplodingBlockingRule(BlockingRule):
414
414
  select distinct
415
415
  {id_expr_l} as {unique_id_col.name_l},
416
416
  {id_expr_r} as {unique_id_col.name_r}
417
- from __splink__df_concat_unnested as l
418
- inner join __splink__df_concat_unnested as r
417
+ from {input_tablename_l} as l
418
+ inner join {input_tablename_r} as r
419
419
  on ({br.blocking_rule_sql})
420
420
  {where_condition}
421
421
  {exclude_sql}
@@ -511,36 +511,69 @@ def materialise_exploded_id_tables(
511
511
  return []
512
512
  exploded_tables = []
513
513
 
514
- pipeline = CTEPipeline()
514
+ first_input_df = next(iter(splink_df_dict.values()))
515
515
 
516
- sql = vertically_concatenate_sql(
517
- splink_df_dict,
518
- salting_required=False,
519
- source_dataset_input_column=source_dataset_input_column,
520
- )
521
- pipeline.enqueue_sql(sql, "__splink__df_concat")
522
- nodes_concat = db_api.sql_pipeline_to_splink_dataframe(pipeline)
523
-
524
- input_columns_set = set(nodes_concat.columns)
516
+ input_columns_set = set(first_input_df.columns)
517
+ if source_dataset_input_column:
518
+ input_columns_set.add(source_dataset_input_column)
525
519
 
526
520
  for br in exploding_blocking_rules:
527
- pipeline = CTEPipeline([nodes_concat])
521
+ pipeline = CTEPipeline()
522
+
523
+ sql = vertically_concatenate_sql(
524
+ splink_df_dict,
525
+ salting_required=False,
526
+ source_dataset_input_column=source_dataset_input_column,
527
+ )
528
+ pipeline.enqueue_sql(sql, "__splink__df_concat")
528
529
  arrays_to_explode_cols = [
529
530
  br._input_column(colname) for colname in br.array_columns_to_explode
530
531
  ]
531
532
 
532
533
  other_cols = input_columns_set - set(arrays_to_explode_cols)
533
534
 
534
- expl_sql = db_api.sql_dialect.explode_arrays_sql(
535
- "__splink__df_concat",
536
- br.array_columns_to_explode,
537
- [col.name for col in other_cols],
538
- )
535
+ if link_type == "two_dataset_link_only":
536
+ if source_dataset_input_column is None:
537
+ raise ValueError(
538
+ "source_dataset_input_column is required for two_dataset_link_only"
539
+ )
540
+
541
+ sqls = split_df_concat_with_tf_into_two_tables_sqls(
542
+ "__splink__df_concat",
543
+ source_dataset_input_column.name,
544
+ )
545
+ pipeline.enqueue_list_of_sqls(sqls)
539
546
 
540
- pipeline.enqueue_sql(
541
- expl_sql,
542
- "__splink__df_concat_unnested",
543
- )
547
+ input_tablename_l = "__splink__df_concat_left_unnested"
548
+ input_tablename_r = "__splink__df_concat_right_unnested"
549
+
550
+ expl_sql_l = db_api.sql_dialect.explode_arrays_sql(
551
+ "__splink__df_concat_left",
552
+ br.array_columns_to_explode,
553
+ [col.name for col in other_cols],
554
+ )
555
+ pipeline.enqueue_sql(expl_sql_l, input_tablename_l)
556
+
557
+ expl_sql_r = db_api.sql_dialect.explode_arrays_sql(
558
+ "__splink__df_concat_right",
559
+ br.array_columns_to_explode,
560
+ [col.name for col in other_cols],
561
+ )
562
+ pipeline.enqueue_sql(expl_sql_r, input_tablename_r)
563
+ else:
564
+ input_tablename_l = "__splink__df_concat_unnested"
565
+ input_tablename_r = "__splink__df_concat_unnested"
566
+
567
+ expl_sql = db_api.sql_dialect.explode_arrays_sql(
568
+ "__splink__df_concat",
569
+ br.array_columns_to_explode,
570
+ [col.name for col in other_cols],
571
+ )
572
+
573
+ pipeline.enqueue_sql(
574
+ expl_sql,
575
+ input_tablename_l,
576
+ )
544
577
 
545
578
  base_name = "__splink__marginal_exploded_ids_blocking_rule"
546
579
  table_name = f"{base_name}_mk_{br.match_key}"
@@ -550,6 +583,8 @@ def materialise_exploded_id_tables(
550
583
  unique_id_input_column=unique_id_input_column,
551
584
  br=br,
552
585
  link_type=link_type,
586
+ input_tablename_l=input_tablename_l,
587
+ input_tablename_r=input_tablename_r,
553
588
  )
554
589
 
555
590
  pipeline.enqueue_sql(sql, table_name)
@@ -71,7 +71,7 @@ def _cc_generate_representatives_loop_cond(
71
71
 
72
72
  from {prev_representatives}
73
73
 
74
- )
74
+ ) as rep_union
75
75
  group by old_rep
76
76
  """
77
77
 
@@ -83,11 +83,11 @@ class SqlglotColumnTreeBuilder:
83
83
  def tree_to_sqlglot_column_tree_builder_args(sqlglot_tree, sqlglot_dialect):
84
84
  args = {"sqlglot_dialect": sqlglot_dialect, "quoted": True}
85
85
  if sqlglot_tree.find(exp.Bracket):
86
- lit = sqlglot_tree.find(exp.Bracket).find(exp.Literal)
87
- if lit.args["is_string"]:
88
- args["bracket_key"] = lit.args["this"]
86
+ lit = sqlglot_tree.find(exp.Bracket).expressions[0]
87
+ if lit.is_string:
88
+ args["bracket_key"] = lit.this
89
89
  else:
90
- args["bracket_index"] = int(lit.args["this"])
90
+ args["bracket_index"] = int(lit.sql())
91
91
 
92
92
  args["column_name"] = sqlglot_tree.find(exp.Identifier).args["this"]
93
93
  return args
@@ -103,6 +103,9 @@ class SqlglotColumnTreeBuilder:
103
103
 
104
104
  valid_signatures = {
105
105
  sqlglot_tree_signature(sqlglot.parse_one("col_name")),
106
+ # negative indices are valid in certain contexts (postgres custom indexing,
107
+ # duckdb), and are treated separately in newer sqlglot versions (28.7.0+)
108
+ sqlglot_tree_signature(sqlglot.parse_one("col_name[-1]")),
106
109
  sqlglot_tree_signature(sqlglot.parse_one("col_name[1]")),
107
110
  sqlglot_tree_signature(sqlglot.parse_one("col_name['lat']")),
108
111
  }
@@ -299,6 +299,7 @@ class SparkAPI(DatabaseAPI[spark_df]):
299
299
  r"__splink__clusters_at_all_thresholds",
300
300
  r"__splink__clustering_output_final",
301
301
  r"__splink__stable_nodes_at_new_threshold",
302
+ r"__splink__filtered_neighbours.*",
302
303
  ]
303
304
 
304
305
  if re.fullmatch(r"|".join(regex_to_persist), templated_name):
File without changes
File without changes
File without changes
File without changes