bigdata-smart-batching 1.3.1__tar.gz → 1.4.0__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 (23) hide show
  1. {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/.gitignore +2 -0
  2. {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/CHANGELOG.md +8 -2
  3. {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/PKG-INFO +3 -2
  4. {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/README.md +2 -1
  5. {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/examples/example.py +48 -0
  6. bigdata_smart_batching-1.4.0/examples/example_non_determinism.py +97 -0
  7. {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/pyproject.toml +1 -1
  8. {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/src/bigdata_smart_batching/search_function.py +13 -1
  9. bigdata_smart_batching-1.3.1/plan.json +0 -20473
  10. {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/LICENSE +0 -0
  11. {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/Makefile +0 -0
  12. {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/docs/smart-batching-architecture.md +0 -0
  13. {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/examples/example_overlapping.py +0 -0
  14. {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/src/bigdata_smart_batching/__init__.py +0 -0
  15. {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/src/bigdata_smart_batching/output_converter.py +0 -0
  16. {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/src/bigdata_smart_batching/smart_batching.py +0 -0
  17. {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/src/bigdata_smart_batching/smart_batching_config.py +0 -0
  18. {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/tests/__init__.py +0 -0
  19. {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/tests/test_config.py +0 -0
  20. {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/tests/test_output_converter.py +0 -0
  21. {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/tests/test_rate_limiter.py +0 -0
  22. {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/tests/test_validation.py +0 -0
  23. {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/uv.lock +0 -0
@@ -110,3 +110,5 @@ Thumbs.db
110
110
  *.csv
111
111
 
112
112
  benchmark/
113
+ *.parquet
114
+ *.json
@@ -6,11 +6,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
8
 
9
- ## [1.3.1] - 2026-05-18
9
+ ## [1.4.0] - 2026-05-20
10
10
 
11
11
  ### Added
12
12
 
13
- - Document-level **source** filters: `INCLUDE` / `EXCLUDE` with a non-empty list of source ID strings, validated with `validate_source_filter`, modeled as `SourceFilter` / `SourceFilterInput` with `SourceMode` (type alias of `CategoryMode`). Serialized to `query.filters.source` on co-mention, volume, and search payloads. `plan_search(..., source=...)` and `source_filter` plumbed through `SmartBatchingPlanner` co-mention and volume flows. Payload builders `build_comention_payload`, `build_volume_payload`, and `build_search_query` accept optional `source_filter`. Types and validator re-exported from the package root.
13
+ - `execute_search(..., basket_filtered_entities=True)`: when enabled, each chunk's `entity_ids` list is filtered to only include entity IDs present in the basket's `query.filters.entity.any_of` list, removing co-mentioned entities that were not explicitly targeted by the basket. Entity IDs are always deduplicated.
14
+
15
+ ## [1.3.1] - 2026-05-19
16
+
17
+ ### Fixed
18
+
19
+ - Now we always retry requests, before we were only retrying on 429 and 403 errors.
14
20
 
15
21
  ## [1.3.0] - 2026-05-12
16
22
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bigdata-smart-batching
3
- Version: 1.3.1
3
+ Version: 1.4.0
4
4
  Summary: High-performance semantic search with intelligent company grouping and parallel execution
5
5
  Project-URL: homepage, https://bigdata.com/api
6
6
  Author-email: "Bigdata.com" <support@ravenpack.com>
@@ -319,6 +319,7 @@ Step 2: EXECUTION
319
319
  | `max_workers` | `int` | `40` | Parallel workers |
320
320
  | `overwrite_chunks_per_basket` | `int \| None` | `None` | Override the proportional chunk allocation |
321
321
  | `second_pass` | `bool` | `False` | Re-query each basket for entities not yet retrieved |
322
+ | `basket_filtered_entities` | `bool` | `False` | When `True`, each chunk's `entity_ids` is filtered to only include IDs present in the basket's `query.filters.entity.any_of` list; entity IDs are always deduplicated |
322
323
 
323
324
  ### Helper Functions
324
325
 
@@ -417,7 +418,7 @@ Ties are resolved using `VOLUME_BUCKET_PRIORITY`: `high > medium > low > very_lo
417
418
  ## Changelog
418
419
 
419
420
  See [CHANGELOG.md](CHANGELOG.md) for release notes. The package is currently at
420
- version **1.2.0**.
421
+ version **1.4.0**.
421
422
 
422
423
  ## License
423
424
 
@@ -303,6 +303,7 @@ Step 2: EXECUTION
303
303
  | `max_workers` | `int` | `40` | Parallel workers |
304
304
  | `overwrite_chunks_per_basket` | `int \| None` | `None` | Override the proportional chunk allocation |
305
305
  | `second_pass` | `bool` | `False` | Re-query each basket for entities not yet retrieved |
306
+ | `basket_filtered_entities` | `bool` | `False` | When `True`, each chunk's `entity_ids` is filtered to only include IDs present in the basket's `query.filters.entity.any_of` list; entity IDs are always deduplicated |
306
307
 
307
308
  ### Helper Functions
308
309
 
@@ -401,7 +402,7 @@ Ties are resolved using `VOLUME_BUCKET_PRIORITY`: `high > medium > low > very_lo
401
402
  ## Changelog
402
403
 
403
404
  See [CHANGELOG.md](CHANGELOG.md) for release notes. The package is currently at
404
- version **1.2.0**.
405
+ version **1.4.0**.
405
406
 
406
407
  ## License
407
408
 
@@ -45,6 +45,54 @@ def main() -> None:
45
45
  )
46
46
  sys.exit(1)
47
47
 
48
+ if False:
49
+ #Compare the results_raw parquet files to see if they are the same but just counting the number of ids
50
+ import pandas as pd
51
+ files = [x for x in os.listdir(".") if x.startswith("results_raw_") and x.endswith("_100pct_basket_6_without_sentiment.parquet")]
52
+ results_dfs = []
53
+ for file in files:
54
+ df = pd.read_parquet(file)
55
+ df_rows = []
56
+ for row in df.to_dict(orient="records"):
57
+ df_rows.append({
58
+ 'doc_id': row['id'],
59
+ 'chunk_cnum': [i['cnum'] for i in row['chunks']],
60
+ })
61
+ results_temp = pd.DataFrame(df_rows)
62
+ # Expand chunks into rows keeping document id, and chunk number
63
+ results_temp = results_temp.explode('chunk_cnum')
64
+ results_temp = results_temp.drop_duplicates()
65
+ #results_temp.sort_values(by=['doc_id', 'chunk_cnum']).to_csv(f"results_raw_{file.split('_')[2]}_100pct_basket_6.csv", index=False)
66
+ results_dfs.append(results_temp)
67
+
68
+ # Merge using id as the key
69
+ merged = results_dfs[0].merge(results_dfs[1], on=['doc_id', 'chunk_cnum'], how='outer', indicator=True)
70
+ print(f"% overlapping chunks: {(len(merged[merged._merge!='both'])/2)/len(merged)*100:.2f}%")
71
+ print('a')
72
+
73
+
74
+ plan = load_plan("pricing_power_evidence.json")
75
+ # Set the query.ranking.params.content_diversification to False
76
+ for basket in plan['baskets']:
77
+ basket['query']['ranking_params']['content_diversification']['enabled'] = False
78
+ #Remove sentiment filter, do not set it to None, remove the key instead
79
+ basket['query']['filters'].pop('sentiment', None)
80
+
81
+ # Keep only basket basket_6_high_20250924_20251022
82
+ plan['baskets'] = [basket for basket in plan['baskets'] if basket['basket_id'] == "basket_6_high_20250924_20251022"]
83
+ results_raw = execute_search(
84
+ search_plan=plan,
85
+ chunk_percentage=1,
86
+ requests_per_minute=450,
87
+ basket_filtered_entities=True,
88
+ )
89
+
90
+ # Store the results in a file but in parquet format
91
+ import json
92
+ import pandas as pd
93
+ df = pd.DataFrame(results_raw)
94
+ df.to_parquet(f"results_raw_{time.time()}_100pct_basket_6_without_sentiment.parquet")
95
+
48
96
  plans = []
49
97
  results_dfs = []
50
98
  for i in range(1):
@@ -0,0 +1,97 @@
1
+ """Execute a single Bigdata search request for basket_6_high_20250924_20251022.
2
+
3
+ Uses only the requests library (no smart-batching helpers). Run twice and compare
4
+ responses to observe search non-determinism.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import pandas as pd
10
+ import requests
11
+
12
+ SEARCH_ENDPOINT = "/v1/search"
13
+ DEFAULT_API_BASE_URL = "https://api.bigdata.com"
14
+
15
+ QUERY = {
16
+ "auto_enrich_filters": False,
17
+ "filters": {
18
+ "timestamp": {
19
+ "start": "2025-09-24T00:00:00Z",
20
+ "end": "2025-10-22T23:59:59Z"
21
+ },
22
+ "entity": {
23
+ "any_of": [
24
+ "12A3A3",
25
+ "619882",
26
+ "9196A2",
27
+ "58CA9A",
28
+ "50070E",
29
+ "E8846E",
30
+ "E09E2B",
31
+ "990AD0",
32
+ "4A6F00",
33
+ "0157B1"
34
+ ],
35
+ "search_in": "BODY"
36
+ },
37
+ "category": {
38
+ "mode": "INCLUDE",
39
+ "values": [
40
+ "news_premium",
41
+ "transcripts"
42
+ ]
43
+ },
44
+ "source": {
45
+ "mode": "EXCLUDE",
46
+ "values": [
47
+ "DFF004"
48
+ ]
49
+ },
50
+ "sentiment": {"ranges": [{"min": 0.1,"max": 1.0}]}
51
+ },
52
+ "ranking_params": {
53
+ "source_boost": 1,
54
+ "freshness_boost": 0,
55
+ "reranker": {
56
+ "enabled": False
57
+ },
58
+ "content_diversification": {"enabled": True}
59
+ },
60
+ "max_chunks": 1000,
61
+ "text": "The company demonstrates pricing power, raises prices without losing volume, or maintains price discipline against competitors."
62
+ }
63
+
64
+ # Query from pricing_power_evidence.json plan, basket basket_6_high_20250924_20251022
65
+
66
+
67
+ def main() -> None:
68
+
69
+ api_key = "bd_v1_UPdNGgq44wBO9XR8THfiGvHd7Km9TCIvDmnT5AiatA9T56"
70
+ url = "https://api.bigdata.com/v1/search"
71
+ headers = {"X-API-KEY": api_key, "Content-Type": "application/json"}
72
+ payload = {"query": QUERY}
73
+
74
+ # Execute the query 10 times and store the results in a df, counting the number of times a doc_id and chunk_cnum appears
75
+ dfs = []
76
+ for i in range(2):
77
+ df_rows = []
78
+ response = requests.post(url, headers=headers, json=payload, timeout=120)
79
+ results = response.json().get("results", [])
80
+ for result in results:
81
+ df_rows.append({
82
+ 'doc_id': result['id'],
83
+ 'chunk_cnum': [i['cnum'] for i in result['chunks']],
84
+ })
85
+ df = pd.DataFrame(df_rows)
86
+ # Expand chunks into rows keeping document id, and chunk number
87
+ df = df.explode('chunk_cnum')
88
+ df = df.drop_duplicates().reset_index(drop=True)
89
+ dfs.append(df)
90
+
91
+ all_df = pd.concat(dfs)
92
+ all_df = all_df.groupby(['doc_id', 'chunk_cnum']).size().reset_index(name='count')
93
+ print(all_df)
94
+
95
+
96
+ if __name__ == "__main__":
97
+ main()
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "bigdata-smart-batching"
3
- version = "1.3.1"
3
+ version = "1.4.0"
4
4
  description = "High-performance semantic search with intelligent company grouping and parallel execution"
5
5
  readme = "README.md"
6
6
  authors = [{ name = "Bigdata.com", email = "support@ravenpack.com" }]
@@ -1247,6 +1247,7 @@ def execute_search(
1247
1247
  second_pass: bool = False,
1248
1248
  rate_limiter: SlidingWindowRateLimiter | None = None,
1249
1249
  concurrency_limiter: ConcurrencySemaphore | None = None,
1250
+ basket_filtered_entities: bool = False,
1250
1251
  ) -> list[dict]:
1251
1252
  """
1252
1253
  Execute search with proportional sampling.
@@ -1270,6 +1271,9 @@ def execute_search(
1270
1271
  concurrency_limiter: Optional pre-built :class:`ConcurrencySemaphore` to
1271
1272
  share with other components. When provided, ``max_workers`` controls
1272
1273
  only the executor's worker count for basket fan-out.
1274
+ basket_filtered_entities: If True, each chunk's ``entity_ids`` will be
1275
+ filtered to only include entity IDs present in the basket's
1276
+ ``query.filters.entity.any_of`` list.
1273
1277
 
1274
1278
  Returns:
1275
1279
  List of document dictionaries (each containing a chunks array).
@@ -1422,7 +1426,15 @@ def execute_search(
1422
1426
  entity_ids = [reporting_entities] if reporting_entities else []
1423
1427
 
1424
1428
  # Store entity information (always set, even if empty)
1425
- chunk["entity_ids"] = entity_ids
1429
+ if basket_filtered_entities:
1430
+ basket_entity_ids = set(
1431
+ basket_info.get("query", {})
1432
+ .get("filters", {})
1433
+ .get("entity", {})
1434
+ .get("any_of", [])
1435
+ )
1436
+ entity_ids = [eid for eid in entity_ids if eid in basket_entity_ids]
1437
+ chunk["entity_ids"] = list(set(entity_ids))
1426
1438
  chunk["primary_entity_id"] = entity_ids[0] if entity_ids else None
1427
1439
 
1428
1440
  logger.info(