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.
- {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/.gitignore +2 -0
- {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/CHANGELOG.md +8 -2
- {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/PKG-INFO +3 -2
- {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/README.md +2 -1
- {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/examples/example.py +48 -0
- bigdata_smart_batching-1.4.0/examples/example_non_determinism.py +97 -0
- {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/pyproject.toml +1 -1
- {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/src/bigdata_smart_batching/search_function.py +13 -1
- bigdata_smart_batching-1.3.1/plan.json +0 -20473
- {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/LICENSE +0 -0
- {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/Makefile +0 -0
- {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/docs/smart-batching-architecture.md +0 -0
- {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/examples/example_overlapping.py +0 -0
- {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/src/bigdata_smart_batching/__init__.py +0 -0
- {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/src/bigdata_smart_batching/output_converter.py +0 -0
- {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/src/bigdata_smart_batching/smart_batching.py +0 -0
- {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/src/bigdata_smart_batching/smart_batching_config.py +0 -0
- {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/tests/__init__.py +0 -0
- {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/tests/test_config.py +0 -0
- {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/tests/test_output_converter.py +0 -0
- {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/tests/test_rate_limiter.py +0 -0
- {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/tests/test_validation.py +0 -0
- {bigdata_smart_batching-1.3.1 → bigdata_smart_batching-1.4.0}/uv.lock +0 -0
|
@@ -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.
|
|
9
|
+
## [1.4.0] - 2026-05-20
|
|
10
10
|
|
|
11
11
|
### Added
|
|
12
12
|
|
|
13
|
-
-
|
|
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
|
+
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.
|
|
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.
|
|
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
|
+
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
|
-
|
|
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(
|