splink 4.0.16__tar.gz → 5.0.0.dev2__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 (171) hide show
  1. {splink-4.0.16 → splink-5.0.0.dev2}/.gitignore +3 -0
  2. {splink-4.0.16 → splink-5.0.0.dev2}/PKG-INFO +7 -12
  3. {splink-4.0.16 → splink-5.0.0.dev2}/README.md +2 -7
  4. {splink-4.0.16 → splink-5.0.0.dev2}/pyproject.toml +51 -24
  5. {splink-4.0.16 → splink-5.0.0.dev2}/splink/__init__.py +1 -1
  6. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/accuracy.py +0 -1
  7. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/blocking.py +167 -85
  8. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/blocking_analysis.py +149 -83
  9. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/blocking_rule_creator.py +0 -11
  10. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/blocking_rule_library.py +3 -47
  11. splink-5.0.0.dev2/splink/internals/charts.py +714 -0
  12. splink-5.0.0.dev2/splink/internals/chunking.py +81 -0
  13. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/clustering.py +4 -4
  14. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/comparison.py +31 -29
  15. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/comparison_level.py +169 -95
  16. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/comparison_level_composition.py +1 -2
  17. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/comparison_level_creator.py +1 -1
  18. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/comparison_level_library.py +16 -3
  19. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/comparison_library.py +1 -0
  20. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/completeness.py +15 -17
  21. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/connected_components.py +1 -3
  22. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/database_api.py +120 -126
  23. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/datasets/splink_datasets.py +8 -5
  24. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/dialects.py +46 -63
  25. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/duckdb/database_api.py +6 -23
  26. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/duckdb/dataframe.py +28 -7
  27. splink-5.0.0.dev2/splink/internals/duckdb/duckdb_helpers/__init__.py +3 -0
  28. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/duckdb/duckdb_helpers/duckdb_helpers.py +17 -0
  29. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/em_training_session.py +48 -21
  30. splink-5.0.0.dev2/splink/internals/estimate_u.py +525 -0
  31. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/expectation_maximisation.py +21 -47
  32. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/settings_jsonschema.json +0 -2
  33. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/splink_vis_utils/splink_vis_utils.js +54 -13
  34. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/find_brs_with_comparison_counts_below_threshold.py +7 -3
  35. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/input_column.py +0 -5
  36. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/labelling_tool.py +2 -3
  37. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/linker.py +20 -55
  38. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/linker_components/clustering.py +2 -6
  39. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/linker_components/evaluation.py +36 -23
  40. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/linker_components/inference.py +265 -137
  41. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/linker_components/misc.py +2 -2
  42. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/linker_components/table_management.py +87 -2
  43. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/linker_components/training.py +22 -11
  44. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/linker_components/visualisations.py +72 -69
  45. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/lower_id_on_lhs.py +7 -2
  46. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/m_from_labels.py +1 -2
  47. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/m_training.py +1 -2
  48. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/misc.py +76 -2
  49. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/one_to_one_clustering.py +1 -3
  50. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/optimise_cost_of_brs.py +3 -2
  51. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/pipeline.py +5 -3
  52. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/postgres/database_api.py +4 -5
  53. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/postgres/dataframe.py +11 -2
  54. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/predict.py +40 -46
  55. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/profile_data.py +13 -9
  56. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/realtime.py +3 -6
  57. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/settings.py +66 -54
  58. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/settings_creator.py +20 -1
  59. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/spark/database_api.py +17 -13
  60. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/spark/dataframe.py +31 -3
  61. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/spark/jar_location.py +2 -13
  62. splink-5.0.0.dev2/splink/internals/spark/spark_helpers/version.py +12 -0
  63. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/splink_comparison_viewer.py +5 -6
  64. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/splink_dataframe.py +61 -3
  65. splink-5.0.0.dev2/splink/internals/splinkdataframe_utils.py +53 -0
  66. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/sqlite/database_api.py +58 -15
  67. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/sqlite/dataframe.py +12 -2
  68. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/term_frequencies.py +135 -137
  69. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/testing.py +9 -4
  70. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/unlinkables.py +1 -1
  71. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/vertically_concatenate.py +13 -21
  72. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/waterfall_chart.py +10 -7
  73. splink-4.0.16/splink/backends/athena.py +0 -3
  74. splink-4.0.16/splink/internals/athena/athena_helpers/athena_transforms.py +0 -14
  75. splink-4.0.16/splink/internals/athena/athena_helpers/athena_utils.py +0 -81
  76. splink-4.0.16/splink/internals/athena/database_api.py +0 -252
  77. splink-4.0.16/splink/internals/athena/dataframe.py +0 -122
  78. splink-4.0.16/splink/internals/charts.py +0 -474
  79. splink-4.0.16/splink/internals/estimate_u.py +0 -242
  80. splink-4.0.16/splink/internals/files/chart_defs/missingness.json +0 -80
  81. splink-4.0.16/splink/internals/spark/__init__.py +0 -0
  82. splink-4.0.16/splink/internals/spark/spark_helpers/__init__.py +0 -0
  83. splink-4.0.16/splink/internals/sqlite/__init__.py +0 -0
  84. {splink-4.0.16 → splink-5.0.0.dev2}/LICENSE +0 -0
  85. {splink-4.0.16 → splink-5.0.0.dev2}/splink/backends/duckdb.py +0 -0
  86. {splink-4.0.16 → splink-5.0.0.dev2}/splink/backends/postgres.py +0 -0
  87. {splink-4.0.16 → splink-5.0.0.dev2}/splink/backends/spark.py +0 -0
  88. {splink-4.0.16 → splink-5.0.0.dev2}/splink/backends/sqlite.py +0 -0
  89. {splink-4.0.16 → splink-5.0.0.dev2}/splink/blocking_analysis.py +0 -0
  90. {splink-4.0.16 → splink-5.0.0.dev2}/splink/blocking_rule_library.py +0 -0
  91. {splink-4.0.16 → splink-5.0.0.dev2}/splink/clustering.py +0 -0
  92. {splink-4.0.16 → splink-5.0.0.dev2}/splink/comparison_level_library.py +0 -0
  93. {splink-4.0.16 → splink-5.0.0.dev2}/splink/comparison_library.py +0 -0
  94. {splink-4.0.16 → splink-5.0.0.dev2}/splink/datasets.py +0 -0
  95. {splink-4.0.16 → splink-5.0.0.dev2}/splink/exploratory.py +0 -0
  96. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/__init__.py +0 -0
  97. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/block_from_labels.py +0 -0
  98. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/blocking_rule_creator_utils.py +0 -0
  99. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/cache_dict_with_logging.py +0 -0
  100. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/cluster_studio.py +0 -0
  101. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/column_expression.py +0 -0
  102. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/comparison_creator.py +0 -0
  103. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/comparison_level_sql.py +0 -0
  104. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/comparison_vector_distribution.py +0 -0
  105. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/comparison_vector_values.py +0 -0
  106. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/constants.py +0 -0
  107. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/cost_of_blocking_rules.py +0 -0
  108. {splink-4.0.16/splink/internals/athena → splink-5.0.0.dev2/splink/internals/databricks}/__init__.py +0 -0
  109. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/databricks/enable_splink.py +0 -0
  110. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/datasets/__init__.py +0 -0
  111. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/datasets/metadata.py +0 -0
  112. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/datasets/utils.py +0 -0
  113. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/default_from_jsonschema.py +0 -0
  114. {splink-4.0.16/splink/internals/athena/athena_helpers → splink-5.0.0.dev2/splink/internals/duckdb}/__init__.py +0 -0
  115. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/edge_metrics.py +0 -0
  116. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/exceptions.py +0 -0
  117. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/DEPENDENCY_LICENSES.txt +0 -0
  118. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/chart_defs/accuracy_chart.json +0 -0
  119. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/chart_defs/blocking_rule_generated_comparisons.json +0 -0
  120. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/chart_defs/comparator_score_chart.json +0 -0
  121. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/chart_defs/comparator_score_threshold_chart.json +0 -0
  122. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/chart_defs/completeness.json +0 -0
  123. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/chart_defs/m_u_parameters_interactive_history.json +0 -0
  124. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/chart_defs/match_weight_histogram.json +0 -0
  125. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/chart_defs/match_weights_interactive_history.json +0 -0
  126. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/chart_defs/match_weights_waterfall.json +0 -0
  127. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/chart_defs/parameter_estimate_comparisons.json +0 -0
  128. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/chart_defs/phonetic_match_chart.json +0 -0
  129. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/chart_defs/precision_recall.json +0 -0
  130. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/chart_defs/probability_two_random_records_match_iteration.json +0 -0
  131. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/chart_defs/profile_data.json +0 -0
  132. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/chart_defs/roc.json +0 -0
  133. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/chart_defs/tf_adjustment_chart.json +0 -0
  134. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/chart_defs/threshold_selection_tool.json +0 -0
  135. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/chart_defs/unlinkables_chart_def.json +0 -0
  136. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/external_js/d3@7.8.5 +0 -0
  137. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/external_js/stdlib.js@5.8.3 +0 -0
  138. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/external_js/vega-embed@6.20.2 +0 -0
  139. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/external_js/vega-lite@5.2.0 +0 -0
  140. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/external_js/vega@5.31.0 +0 -0
  141. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/labelling_tool/slt.js +0 -0
  142. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/labelling_tool/template.j2 +0 -0
  143. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/spark_jars/scala-udf-similarity-0.1.2_spark3.x.jar +0 -0
  144. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/spark_jars/scala-udf-similarity-0.2.0_spark4.x.jar +0 -0
  145. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/splink_cluster_studio/cluster_template.j2 +0 -0
  146. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/splink_cluster_studio/custom.css +0 -0
  147. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/splink_comparison_viewer/custom.css +0 -0
  148. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/splink_comparison_viewer/template.j2 +0 -0
  149. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/files/templates/single_chart_template.html +0 -0
  150. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/find_matches_to_new_records.py +0 -0
  151. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/graph_metrics.py +0 -0
  152. {splink-4.0.16/splink/internals/databricks → splink-5.0.0.dev2/splink/internals/linker_components}/__init__.py +0 -0
  153. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/logging_messages.py +0 -0
  154. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/m_u_records_to_parameters.py +0 -0
  155. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/match_weights_histogram.py +0 -0
  156. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/parse_sql.py +0 -0
  157. {splink-4.0.16/splink/internals/duckdb → splink-5.0.0.dev2/splink/internals/postgres}/__init__.py +0 -0
  158. {splink-4.0.16/splink/internals/duckdb/duckdb_helpers → splink-5.0.0.dev2/splink/internals/settings_validation}/__init__.py +0 -0
  159. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/settings_validation/log_invalid_columns.py +0 -0
  160. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/settings_validation/settings_column_cleaner.py +0 -0
  161. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/settings_validation/settings_validation_log_strings.py +0 -0
  162. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/settings_validation/valid_types.py +0 -0
  163. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/similarity_analysis.py +0 -0
  164. {splink-4.0.16/splink/internals/linker_components → splink-5.0.0.dev2/splink/internals/spark}/__init__.py +0 -0
  165. {splink-4.0.16/splink/internals/postgres → splink-5.0.0.dev2/splink/internals/spark/spark_helpers}/__init__.py +0 -0
  166. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/spark/spark_helpers/custom_spark_dialect.py +0 -0
  167. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/sql_transform.py +0 -0
  168. {splink-4.0.16/splink/internals/settings_validation → splink-5.0.0.dev2/splink/internals/sqlite}/__init__.py +0 -0
  169. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/unique_id_concat.py +0 -0
  170. {splink-4.0.16 → splink-5.0.0.dev2}/splink/internals/validate_jsonschema.py +0 -0
  171. {splink-4.0.16 → splink-5.0.0.dev2}/splink/py.typed +0 -0
@@ -163,6 +163,8 @@ cython_debug/
163
163
 
164
164
  *.parquet
165
165
  *.csv
166
+ *.json
167
+
166
168
 
167
169
  # html files opt-in only
168
170
  *.html
@@ -177,5 +179,6 @@ cython_debug/
177
179
  splink_db
178
180
  splink_db_log
179
181
  spark-warehouse
182
+ *.ddb*
180
183
 
181
184
  scripts/pyspelling/dictionary.dic
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: splink
3
- Version: 4.0.16
3
+ Version: 5.0.0.dev2
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
@@ -13,18 +13,18 @@ Requires-Dist: altair>=5.0.1
13
13
  Requires-Dist: duckdb>=0.9.2
14
14
  Requires-Dist: igraph>=0.11.2
15
15
  Requires-Dist: jinja2>=3.0.3
16
- Requires-Dist: numpy>=1.19.3
17
- Requires-Dist: pandas>=1.3.5
18
16
  Requires-Dist: sqlglot>=17.6.0
19
- Provides-Extra: athena
20
- Requires-Dist: awswrangler; extra == 'athena'
21
17
  Provides-Extra: postgres
22
18
  Requires-Dist: psycopg2-binary>=2.9.0; extra == 'postgres'
23
19
  Requires-Dist: sqlalchemy>=2.0.0; extra == 'postgres'
20
+ Provides-Extra: pyarrow
21
+ Requires-Dist: pyarrow>=15.0.0; extra == 'pyarrow'
24
22
  Provides-Extra: pyspark
25
23
  Requires-Dist: pyspark>=3.5.0; extra == 'pyspark'
26
24
  Provides-Extra: spark
27
25
  Requires-Dist: pyspark>=3.5.0; extra == 'spark'
26
+ Provides-Extra: sqlite
27
+ Requires-Dist: rapidfuzz>=3.10.0; extra == 'sqlite'
28
28
  Description-Content-Type: text/markdown
29
29
 
30
30
  <p align="center">
@@ -50,7 +50,7 @@ It is used widely by within government, academia and the private sector - see [u
50
50
 
51
51
  ⚡ **Speed:** Capable of linking a million records on a laptop in around a minute.<br>
52
52
  🎯 **Accuracy:** Support for term frequency adjustments and user-defined fuzzy matching logic.<br>
53
- 🌐 **Scalability:** Execute linkage in Python (using DuckDB) or big-data backends like AWS Athena or Spark for 100+ million records.<br>
53
+ 🌐 **Scalability:** Execute linkage in Python (using DuckDB) or big-data backends like Spark for 100+ million records.<br>
54
54
  🎓 **Unsupervised Learning:** No training data is required for model training.<br>
55
55
  📊 **Interactive Outputs:** A suite of interactive visualisations help users understand their model and diagnose problems.<br>
56
56
 
@@ -104,7 +104,7 @@ conda install -c conda-forge splink
104
104
  ### Installing Splink for Specific Backends
105
105
 
106
106
 
107
- For projects requiring specific backends, Splink offers optional installations for **Spark**, **Athena**, and **PostgreSQL**. These can be installed by appending the backend name in brackets to the pip install command:
107
+ For projects requiring specific backends, Splink offers optional installations for **Spark** and **PostgreSQL**. These can be installed by appending the backend name in brackets to the pip install command:
108
108
  ```sh
109
109
  pip install 'splink[{backend}]'
110
110
  ```
@@ -117,11 +117,6 @@ pip install 'splink[{backend}]'
117
117
  pip install 'splink[spark]'
118
118
  ```
119
119
 
120
- #### Athena
121
- ```sh
122
- pip install 'splink[athena]'
123
- ```
124
-
125
120
  #### PostgreSQL
126
121
  ```sh
127
122
  pip install 'splink[postgres]'
@@ -21,7 +21,7 @@ It is used widely by within government, academia and the private sector - see [u
21
21
 
22
22
  ⚡ **Speed:** Capable of linking a million records on a laptop in around a minute.<br>
23
23
  🎯 **Accuracy:** Support for term frequency adjustments and user-defined fuzzy matching logic.<br>
24
- 🌐 **Scalability:** Execute linkage in Python (using DuckDB) or big-data backends like AWS Athena or Spark for 100+ million records.<br>
24
+ 🌐 **Scalability:** Execute linkage in Python (using DuckDB) or big-data backends like Spark for 100+ million records.<br>
25
25
  🎓 **Unsupervised Learning:** No training data is required for model training.<br>
26
26
  📊 **Interactive Outputs:** A suite of interactive visualisations help users understand their model and diagnose problems.<br>
27
27
 
@@ -75,7 +75,7 @@ conda install -c conda-forge splink
75
75
  ### Installing Splink for Specific Backends
76
76
 
77
77
 
78
- For projects requiring specific backends, Splink offers optional installations for **Spark**, **Athena**, and **PostgreSQL**. These can be installed by appending the backend name in brackets to the pip install command:
78
+ For projects requiring specific backends, Splink offers optional installations for **Spark** and **PostgreSQL**. These can be installed by appending the backend name in brackets to the pip install command:
79
79
  ```sh
80
80
  pip install 'splink[{backend}]'
81
81
  ```
@@ -88,11 +88,6 @@ pip install 'splink[{backend}]'
88
88
  pip install 'splink[spark]'
89
89
  ```
90
90
 
91
- #### Athena
92
- ```sh
93
- pip install 'splink[athena]'
94
- ```
95
-
96
91
  #### PostgreSQL
97
92
  ```sh
98
93
  pip install 'splink[postgres]'
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "splink"
3
- version = "4.0.16"
3
+ version = "5.0.0.dev2"
4
4
  description = "Fast probabilistic data linkage at scale"
5
5
  authors = [
6
6
  { name = "Robin Linacre", email = "robinlinacre@hotmail.com" },
@@ -14,42 +14,47 @@ requires-python = ">=3.9.0,<4.0.0"
14
14
  readme = "README.md"
15
15
  license = "MIT"
16
16
  dependencies = [
17
- "pandas>=1.3.5",
18
17
  "duckdb>=0.9.2",
19
18
  "sqlglot>=17.6.0",
20
19
  "altair>=5.0.1",
21
20
  "Jinja2>=3.0.3",
22
- "numpy>=1.19.3",
23
21
  "igraph>=0.11.2",
24
22
  ]
25
23
 
26
24
  [project.optional-dependencies]
27
25
  pyspark = ["pyspark>=3.5.0"]
28
26
  spark = ["pyspark>=3.5.0"]
29
- athena = ["awswrangler"]
27
+ # sqlite doesn't _require_ this functionality, but it's used if we want to use fuzzy levels
28
+ sqlite = ["rapidfuzz>=3.10.0"]
30
29
  postgres = ["sqlalchemy>=2.0.0", "psycopg2-binary>=2.9.0"]
30
+ pyarrow = ["pyarrow>=15.0.0"]
31
+ # TODO: pandas optional
31
32
 
32
33
  [project.urls]
33
34
  Homepage = "https://github.com/moj-analytical-services/splink"
34
35
  Repository = "https://github.com/moj-analytical-services/splink"
35
36
 
36
37
  [dependency-groups]
37
- # dummy 'core' group to allow us to declare conflict with athena
38
- # awswrangler upper-pins packages including pyarrow, so ruins our resolution otherwise
39
- # additionally allows us to easily check package functionality with just these installed
38
+ # allows us to easily check package functionality with just these installed
40
39
  # (and not the rest of our required dependencies)
41
- core = ["sqlglot", "pandas"]
40
+ core = ["sqlglot", "duckdb"]
42
41
  demos = [
43
42
  "ipywidgets>=8.1.7",
43
+ "jupytext>=1.18.1",
44
44
  "nbmake>=1.5.5",
45
+ "pseudopeople>=1.2.6",
45
46
  "pytest-xdist>=3.6.1",
46
47
  ]
48
+ # dev deliberately doesn't include spark, so we can opt in to different spark versions
47
49
  dev = [
48
- "tabulate>=0.8.9",
49
- "pyspark>=3.5.0",
50
- "sqlalchemy>=2.0.0",
51
- "psycopg2-binary>=2.9.0",
50
+ { "include-group" = "linting" },
51
+ { "include-group" = "testing-core" },
52
+ { "include-group" = "typechecking" },
52
53
  ]
54
+ spark-3 = [
55
+ "pyspark<4; python_version < '3.12'",
56
+ ]
57
+ spark-4 = ["pyspark>=4.0.0"]
53
58
  docs = [
54
59
  "griffe>=1.4.0",
55
60
  # keep jinja2 relaxed so it doesn't constrain us in rest of dev
@@ -68,32 +73,45 @@ docs = [
68
73
  "pymdown-extensions>=10.15",
69
74
  ]
70
75
  linting = ["ruff>=0.4.2,<0.5"]
71
- testing = [
76
+ pandas = ["pandas>=1.3.5", "numpy>=1.19.3"]
77
+ postgres = [
78
+ "psycopg2-binary>=2.9.0",
79
+ "sqlalchemy>=2.0.0",
80
+ ]
81
+ sqlite = [
82
+ "rapidfuzz>=3.10.0",
83
+ ]
84
+ testing-core = [
72
85
  "pytest>=7.3",
73
- "pyarrow>=7.0.0",
86
+ "pyarrow>=15.0.0",
74
87
  "networkx>=2.5.1",
75
- "rapidfuzz>=3.0.0",
76
88
  "pytest-cov>=5.0.0",
89
+ { "include-group" = "postgres" },
90
+ { "include-group" = "sqlite" },
91
+ # TODO: temporary measure until we can depanda tests
92
+ { "include-group" = "pandas" },
93
+ ]
94
+ testing = [
95
+ { "include-group" = "testing-core" },
96
+ { "include-group" = "spark-4" },
77
97
  ]
78
98
  typechecking = ["mypy==1.9.0"]
99
+ # we will migrate to ty, but won't happen all at once, so run in parallel
100
+ typechecking-dev = [
101
+ "ty>=0.0.21",
102
+ ]
79
103
 
80
104
  [tool.uv]
81
105
  default-groups = [
82
- "core",
83
106
  "dev",
84
- "linting",
85
- "testing",
86
- "typechecking",
107
+ "spark-4"
87
108
  ]
88
109
  conflicts = [
89
110
  [
90
- { group = "core" },
91
- { extra = "athena" }
111
+ { group = "spark-4" },
112
+ { group = "spark-3" },
92
113
  ]
93
114
  ]
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
115
 
98
116
  [tool.uv.dependency-groups]
99
117
  docs = { requires-python = ">=3.13" }
@@ -130,6 +148,13 @@ lint.ignore = [
130
148
  "B006", # Do not use mutable data structures for argument defaults"
131
149
  ]
132
150
 
151
+ # really we want to lint docs with a looser set of rules (such as not enforcing the same line length)
152
+ # for now we simply exclude
153
+ exclude = [
154
+ "docs",
155
+ ]
156
+
157
+
133
158
  [tool.pytest.ini_options]
134
159
  addopts = ["-m default"]
135
160
  markers = [
@@ -147,6 +172,8 @@ markers = [
147
172
  "sqlite_only",
148
173
  "postgres",
149
174
  "postgres_only",
175
+ # optional dependendencies beyond backends
176
+ "needs_pandas",
150
177
  ]
151
178
 
152
179
  [tool.mypy]
@@ -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.16"
59
+ __version__ = "5.0.0.dev2"
60
60
 
61
61
 
62
62
  __all__ = [
@@ -422,7 +422,6 @@ def predictions_from_sample_of_pairwise_labels_sql(linker, labels_tablename):
422
422
  sqls_2 = predict_from_comparison_vectors_sqls_using_settings(
423
423
  linker._settings_obj,
424
424
  include_clerical_match_score=True,
425
- sql_infinity_expression=linker._infinity_expression,
426
425
  )
427
426
 
428
427
  sqls.extend(sqls_2)
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import logging
4
+ import time
4
5
  from typing import TYPE_CHECKING, Any, List, Literal, Optional, TypedDict
5
6
 
6
7
  from sqlglot import parse_one
@@ -9,6 +10,7 @@ from sqlglot.optimizer.eliminate_joins import join_condition
9
10
  from sqlglot.optimizer.optimizer import optimize
10
11
  from sqlglot.optimizer.simplify import flatten
11
12
 
13
+ from splink.internals.chunking import _chunk_assignment_sql
12
14
  from splink.internals.database_api import DatabaseAPISubClass
13
15
  from splink.internals.dialects import SplinkDialect
14
16
  from splink.internals.input_column import InputColumn
@@ -38,7 +40,6 @@ backend_link_type_options = Literal[
38
40
  class BlockingRuleDict(TypedDict):
39
41
  blocking_rule: str
40
42
  sql_dialect: str
41
- salting_partitions: int | None
42
43
  arrays_to_explode: list[str] | None
43
44
 
44
45
 
@@ -52,19 +53,8 @@ def blocking_rule_to_obj(br: BlockingRule | BlockingRuleDict) -> BlockingRule:
52
53
  sql_dialect_str = br.get("sql_dialect", None)
53
54
  if sql_dialect_str is None:
54
55
  raise ValueError("Must provide a valid sql_dialect")
55
- salting_partitions = br.get("salting_partitions", None)
56
- arrays_to_explode = br.get("arrays_to_explode", None)
57
-
58
- if arrays_to_explode is not None and salting_partitions is not None:
59
- raise ValueError(
60
- "Splink does not support blocking rules that are "
61
- " both salted and exploding"
62
- )
63
56
 
64
- if salting_partitions is not None:
65
- return SaltedBlockingRule(
66
- blocking_rule, sql_dialect_str, salting_partitions
67
- )
57
+ arrays_to_explode = br.get("arrays_to_explode", None)
68
58
 
69
59
  if arrays_to_explode is not None:
70
60
  return ExplodingBlockingRule(
@@ -97,7 +87,6 @@ def _columns_needed_for_blocking(
97
87
  )
98
88
 
99
89
  for br in blocking_rules:
100
- # Preserve first-seen column order so the projected blocking SQL is stable.
101
90
  parsed_columns = parse_columns_in_sql(
102
91
  br.blocking_rule_sql, sqlglot_dialect=br.sqlglot_dialect
103
92
  )
@@ -125,9 +114,13 @@ class BlockingRule:
125
114
  self.preceding_rules: List[BlockingRule] = []
126
115
 
127
116
  @property
128
- def sqlglot_dialect(self):
117
+ def sqlglot_dialect(self) -> str:
129
118
  return SplinkDialect.from_string(self._sql_dialect_str).sqlglot_dialect
130
119
 
120
+ @property
121
+ def sql_dialect(self) -> SplinkDialect:
122
+ return SplinkDialect.from_string(self._sql_dialect_str)
123
+
131
124
  def _input_column(self, name: str) -> InputColumn:
132
125
  """Create an InputColumn with this blocking rule's dialect."""
133
126
  return InputColumn(name, sqlglot_dialect_str=self.sqlglot_dialect)
@@ -316,70 +309,6 @@ class BlockingRule:
316
309
  return f"{self.descr} blocking rule using SQL: {sql}"
317
310
 
318
311
 
319
- class SaltedBlockingRule(BlockingRule):
320
- def __init__(
321
- self,
322
- blocking_rule: str,
323
- sqlglot_dialect: str,
324
- salting_partitions: int = 1,
325
- ):
326
- if salting_partitions is None or salting_partitions <= 1:
327
- raise ValueError("Salting partitions must be specified and > 1")
328
-
329
- super().__init__(blocking_rule, sqlglot_dialect)
330
- self.salting_partitions = salting_partitions
331
-
332
- def as_dict(self):
333
- output = super().as_dict()
334
- output["salting_partitions"] = self.salting_partitions
335
- return output
336
-
337
- def _as_completed_dict(self):
338
- return self.as_dict()
339
-
340
- def _salting_condition(self, salt):
341
- return f"AND ceiling(l.__splink_salt * {self.salting_partitions}) = {salt + 1}"
342
-
343
- def create_blocked_pairs_sql(
344
- self,
345
- *,
346
- source_dataset_input_column: Optional[InputColumn],
347
- unique_id_input_column: InputColumn,
348
- input_tablename_l: str,
349
- input_tablename_r: str,
350
- where_condition: str,
351
- ) -> str:
352
- if source_dataset_input_column:
353
- unique_id_columns = [source_dataset_input_column, unique_id_input_column]
354
- else:
355
- unique_id_columns = [unique_id_input_column]
356
-
357
- uid_l_expr = _composite_unique_id_from_nodes_sql(unique_id_columns, "l")
358
- uid_r_expr = _composite_unique_id_from_nodes_sql(unique_id_columns, "r")
359
-
360
- sqls = []
361
- exclude_sql = self.exclude_pairs_generated_by_all_preceding_rules_sql(
362
- source_dataset_input_column, unique_id_input_column
363
- )
364
- for salt in range(self.salting_partitions):
365
- salt_condition = self._salting_condition(salt)
366
- sql = f"""
367
- select
368
- '{self.match_key}' as match_key,
369
- {uid_l_expr} as join_key_l,
370
- {uid_r_expr} as join_key_r
371
- from {input_tablename_l} as l
372
- inner join {input_tablename_r} as r
373
- on
374
- ({self.blocking_rule_sql} {salt_condition})
375
- {where_condition}
376
- {exclude_sql}
377
- """
378
-
379
- sqls.append(sql)
380
- return " UNION ALL ".join(sqls)
381
-
382
-
383
312
  def _explode_arrays_sql(db_api, tbl_name, columns_to_explode, other_columns_to_retain):
384
313
  return db_api.sql_dialect.explode_arrays_sql(
385
314
  tbl_name, columns_to_explode, other_columns_to_retain
@@ -411,10 +340,18 @@ class ExplodingBlockingRule(BlockingRule):
411
340
  link_type: "LinkTypeLiteralType",
412
341
  input_tablename_l: str,
413
342
  input_tablename_r: str,
343
+ left_chunk: tuple[int, int] | None = None,
344
+ right_chunk: tuple[int, int] | None = None,
414
345
  ) -> str:
415
346
  """generates a table of the marginal id pairs from the exploded blocking rule
416
347
  i.e. pairs are only created that match this blocking rule and NOT any of
417
348
  the preceding blocking rules
349
+
350
+ Args:
351
+ left_chunk: Optional tuple of (chunk_number, total_chunks) for filtering
352
+ left side records.
353
+ right_chunk: Optional tuple of (chunk_number, total_chunks) for filtering
354
+ right side records.
418
355
  """
419
356
 
420
357
  unique_id_col = unique_id_input_column
@@ -422,7 +359,13 @@ class ExplodingBlockingRule(BlockingRule):
422
359
  source_dataset_input_column, unique_id_input_column
423
360
  )
424
361
 
425
- where_condition = _sql_gen_where_condition(link_type, unique_id_input_columns)
362
+ where_condition = _sql_gen_where_condition(
363
+ link_type,
364
+ unique_id_input_columns,
365
+ left_chunk=left_chunk,
366
+ right_chunk=right_chunk,
367
+ sql_dialect=self.sql_dialect,
368
+ )
426
369
 
427
370
  id_expr_l = _composite_unique_id_from_nodes_sql(unique_id_input_columns, "l")
428
371
  id_expr_r = _composite_unique_id_from_nodes_sql(unique_id_input_columns, "r")
@@ -522,7 +465,17 @@ def materialise_exploded_id_tables(
522
465
  splink_df_dict: dict[str, SplinkDataFrame],
523
466
  source_dataset_input_column: Optional[InputColumn],
524
467
  unique_id_input_column: InputColumn,
468
+ left_chunk: tuple[int, int] | None = None,
469
+ right_chunk: tuple[int, int] | None = None,
525
470
  ) -> list[ExplodingBlockingRule]:
471
+ """Materialise exploded ID pair tables for exploding blocking rules.
472
+
473
+ Args:
474
+ left_chunk: Optional tuple of (chunk_number, total_chunks) for filtering
475
+ left side records.
476
+ right_chunk: Optional tuple of (chunk_number, total_chunks) for filtering
477
+ right side records.
478
+ """
526
479
  exploding_blocking_rules = [
527
480
  br for br in blocking_rules if isinstance(br, ExplodingBlockingRule)
528
481
  ]
@@ -573,9 +526,7 @@ def materialise_exploded_id_tables(
573
526
  pipeline.enqueue_sql(expl_sql_r, input_tablename_r)
574
527
  else:
575
528
  sql = vertically_concatenate_sql(
576
- splink_df_dict,
577
- salting_required=False,
578
- source_dataset_input_column=source_dataset_input_column,
529
+ splink_df_dict, source_dataset_input_column=source_dataset_input_column
579
530
  )
580
531
  pipeline.enqueue_sql(sql, "__splink__df_concat")
581
532
 
@@ -603,6 +554,8 @@ def materialise_exploded_id_tables(
603
554
  link_type=link_type,
604
555
  input_tablename_l=input_tablename_l,
605
556
  input_tablename_r=input_tablename_r,
557
+ left_chunk=left_chunk,
558
+ right_chunk=right_chunk,
606
559
  )
607
560
 
608
561
  pipeline.enqueue_sql(sql, table_name)
@@ -614,8 +567,107 @@ def materialise_exploded_id_tables(
614
567
  return exploding_blocking_rules
615
568
 
616
569
 
570
+ def compute_blocked_pairs_from_concat_with_tf(
571
+ *,
572
+ pipeline: CTEPipeline,
573
+ db_api: DatabaseAPISubClass,
574
+ splink_df_dict: dict[str, SplinkDataFrame],
575
+ blocking_rules: list[BlockingRule],
576
+ link_type: "LinkTypeLiteralType",
577
+ source_dataset_input_column: Optional[InputColumn],
578
+ unique_id_input_column: InputColumn,
579
+ df_concat_with_tf_table_name: str = "__splink__df_concat_with_tf",
580
+ left_chunk: tuple[int, int] | None = None,
581
+ right_chunk: tuple[int, int] | None = None,
582
+ ) -> SplinkDataFrame:
583
+ """Compute __splink__blocked_id_pairs from df_concat_with_tf.
584
+
585
+ Enqueues SQL to the pipeline, materialises the result, and cleans up
586
+ any exploded ID pair tables used by exploding blocking rules.
587
+
588
+ Args:
589
+ left_chunk: Optional tuple of (chunk_number, total_chunks) for filtering
590
+ left side records.
591
+ right_chunk: Optional tuple of (chunk_number, total_chunks) for filtering
592
+ right side records.
593
+
594
+ Returns:
595
+ SplinkDataFrame: The materialised blocked pairs table.
596
+ """
597
+ start_time = time.time()
598
+
599
+ blocking_input_tablename_l = df_concat_with_tf_table_name
600
+ blocking_input_tablename_r = df_concat_with_tf_table_name
601
+ effective_link_type = link_type
602
+
603
+ # Optimisation for 2-dataset link_only
604
+ if len(splink_df_dict) == 2 and link_type == "link_only":
605
+ if not source_dataset_input_column:
606
+ raise ValueError(
607
+ "link_type='link_only' with two input tables requires a "
608
+ "source_dataset column"
609
+ )
610
+
611
+ input_columns = _columns_needed_for_blocking(
612
+ blocking_rules=blocking_rules,
613
+ source_dataset_input_column=source_dataset_input_column,
614
+ unique_id_input_column=unique_id_input_column,
615
+ )
616
+ left_sql, right_sql = select_two_dataset_link_only_input_tables_sqls(
617
+ splink_df_dict,
618
+ input_columns=input_columns,
619
+ source_dataset_input_column=source_dataset_input_column,
620
+ )
621
+ pipeline.enqueue_sql(left_sql, f"{df_concat_with_tf_table_name}_left")
622
+ pipeline.enqueue_sql(right_sql, f"{df_concat_with_tf_table_name}_right")
623
+
624
+ blocking_input_tablename_l = f"{df_concat_with_tf_table_name}_left"
625
+ blocking_input_tablename_r = f"{df_concat_with_tf_table_name}_right"
626
+ effective_link_type = "two_dataset_link_only"
627
+
628
+ materialise_exploded_id_tables(
629
+ link_type=effective_link_type,
630
+ blocking_rules=blocking_rules,
631
+ db_api=db_api,
632
+ splink_df_dict=splink_df_dict,
633
+ source_dataset_input_column=source_dataset_input_column,
634
+ unique_id_input_column=unique_id_input_column,
635
+ left_chunk=left_chunk,
636
+ right_chunk=right_chunk,
637
+ )
638
+
639
+ sqls = block_using_rules_sqls(
640
+ input_tablename_l=blocking_input_tablename_l,
641
+ input_tablename_r=blocking_input_tablename_r,
642
+ blocking_rules=blocking_rules,
643
+ link_type=effective_link_type,
644
+ source_dataset_input_column=source_dataset_input_column,
645
+ unique_id_input_column=unique_id_input_column,
646
+ left_chunk=left_chunk,
647
+ right_chunk=right_chunk,
648
+ )
649
+
650
+ pipeline.enqueue_list_of_sqls(sqls)
651
+
652
+ blocked_pairs = db_api.sql_pipeline_to_splink_dataframe(pipeline)
653
+
654
+ # Clean up exploded ID pair tables
655
+ for br in blocking_rules:
656
+ if isinstance(br, ExplodingBlockingRule):
657
+ br.drop_materialised_id_pairs_dataframe()
658
+
659
+ blocking_time = time.time() - start_time
660
+ logger.info(f"Blocking time: {blocking_time:.2f} seconds")
661
+
662
+ return blocked_pairs
663
+
664
+
617
665
  def _sql_gen_where_condition(
618
- link_type: backend_link_type_options, unique_id_cols: List[InputColumn]
666
+ link_type: backend_link_type_options,
667
+ unique_id_cols: List[InputColumn],
668
+ left_chunk: tuple[int, int] | None = None,
669
+ right_chunk: tuple[int, int] | None = None,
670
+ sql_dialect: "SplinkDialect | None" = None,
619
671
  ) -> str:
620
672
  id_expr_l = _composite_unique_id_from_nodes_sql(unique_id_cols, "l")
621
673
  id_expr_r = _composite_unique_id_from_nodes_sql(unique_id_cols, "r")
@@ -631,6 +683,19 @@ def _sql_gen_where_condition(
631
683
  f"and l.{source_dataset_col.name} != r.{source_dataset_col.name}"
632
684
  )
633
685
 
686
+ # Add chunk filtering if specified
687
+ if left_chunk is not None and sql_dialect is not None:
688
+ chunk_num, total_chunks = left_chunk
689
+ where_condition += _chunk_assignment_sql(
690
+ unique_id_cols, chunk_num, total_chunks, "l", sql_dialect
691
+ )
692
+
693
+ if right_chunk is not None and sql_dialect is not None:
694
+ chunk_num, total_chunks = right_chunk
695
+ where_condition += _chunk_assignment_sql(
696
+ unique_id_cols, chunk_num, total_chunks, "r", sql_dialect
697
+ )
698
+
634
699
  return where_condition
635
700
 
636
701
 
@@ -642,6 +707,8 @@ def block_using_rules_sqls(
642
707
  link_type: "LinkTypeLiteralType",
643
708
  source_dataset_input_column: Optional[InputColumn],
644
709
  unique_id_input_column: InputColumn,
710
+ left_chunk: tuple[int, int] | None = None,
711
+ right_chunk: tuple[int, int] | None = None,
645
712
  ) -> list[dict[str, str]]:
646
713
  """Use the blocking rules specified in the linker's settings object to
647
714
  generate a SQL statement that will create pairwise record comparions
@@ -649,6 +716,13 @@ def block_using_rules_sqls(
649
716
 
650
717
  Where there are multiple blocking rules, the SQL statement contains logic
651
718
  so that duplicate comparisons are not generated.
719
+
720
+ Args:
721
+ left_chunk: Optional tuple of (chunk_number, total_chunks) for filtering
722
+ left side records. Requires dialect to be provided.
723
+ right_chunk: Optional tuple of (chunk_number, total_chunks) for filtering
724
+ right side records. Requires dialect to be provided.
725
+ dialect: SQL dialect, required when using chunking parameters.
652
726
  """
653
727
 
654
728
  sqls = []
@@ -657,7 +731,15 @@ def block_using_rules_sqls(
657
731
  source_dataset_input_column, unique_id_input_column
658
732
  )
659
733
 
660
- where_condition = _sql_gen_where_condition(link_type, unique_id_input_columns)
734
+ sql_dialect = blocking_rules[0].sql_dialect if blocking_rules else None
735
+
736
+ where_condition = _sql_gen_where_condition(
737
+ link_type,
738
+ unique_id_input_columns,
739
+ left_chunk=left_chunk,
740
+ right_chunk=right_chunk,
741
+ sql_dialect=sql_dialect,
742
+ )
661
743
 
662
744
  # Cover the case where there are no blocking rules
663
745
  # This is a bit of a hack where if you do a self-join on 'true'