bigdata-smart-batching 1.4.1__tar.gz → 1.5.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 (22) hide show
  1. bigdata_smart_batching-1.4.1/README.md → bigdata_smart_batching-1.5.0/PKG-INFO +20 -1
  2. bigdata_smart_batching-1.4.1/PKG-INFO → bigdata_smart_batching-1.5.0/README.md +4 -17
  3. {bigdata_smart_batching-1.4.1 → bigdata_smart_batching-1.5.0}/examples/example.py +21 -19
  4. {bigdata_smart_batching-1.4.1 → bigdata_smart_batching-1.5.0}/pyproject.toml +9 -1
  5. {bigdata_smart_batching-1.4.1 → bigdata_smart_batching-1.5.0}/src/bigdata_smart_batching/__init__.py +2 -0
  6. {bigdata_smart_batching-1.4.1 → bigdata_smart_batching-1.5.0}/src/bigdata_smart_batching/output_converter.py +3 -1
  7. {bigdata_smart_batching-1.4.1 → bigdata_smart_batching-1.5.0}/src/bigdata_smart_batching/search_function.py +27 -13
  8. bigdata_smart_batching-1.4.1/CHANGELOG.md +0 -165
  9. bigdata_smart_batching-1.4.1/Makefile +0 -19
  10. bigdata_smart_batching-1.4.1/docs/smart-batching-architecture.md +0 -481
  11. bigdata_smart_batching-1.4.1/examples/example_non_determinism.py +0 -97
  12. bigdata_smart_batching-1.4.1/examples/example_overlapping.py +0 -185
  13. bigdata_smart_batching-1.4.1/tests/__init__.py +0 -0
  14. bigdata_smart_batching-1.4.1/tests/test_config.py +0 -30
  15. bigdata_smart_batching-1.4.1/tests/test_output_converter.py +0 -82
  16. bigdata_smart_batching-1.4.1/tests/test_rate_limiter.py +0 -120
  17. bigdata_smart_batching-1.4.1/tests/test_validation.py +0 -342
  18. bigdata_smart_batching-1.4.1/uv.lock +0 -1045
  19. {bigdata_smart_batching-1.4.1 → bigdata_smart_batching-1.5.0}/.gitignore +0 -0
  20. {bigdata_smart_batching-1.4.1 → bigdata_smart_batching-1.5.0}/LICENSE +0 -0
  21. {bigdata_smart_batching-1.4.1 → bigdata_smart_batching-1.5.0}/src/bigdata_smart_batching/smart_batching.py +0 -0
  22. {bigdata_smart_batching-1.4.1 → bigdata_smart_batching-1.5.0}/src/bigdata_smart_batching/smart_batching_config.py +0 -0
@@ -1,3 +1,19 @@
1
+ Metadata-Version: 2.5
2
+ Name: bigdata-smart-batching
3
+ Version: 1.5.0
4
+ Summary: High-performance semantic search with intelligent company grouping and parallel execution
5
+ Project-URL: homepage, https://bigdata.com/api
6
+ Author-email: "Bigdata.com" <support@ravenpack.com>
7
+ License: MIT
8
+ License-File: LICENSE
9
+ Requires-Python: <4.0,>=3.11
10
+ Requires-Dist: matplotlib>=3.7
11
+ Requires-Dist: numpy>=1.24
12
+ Requires-Dist: pandas>=2.0
13
+ Requires-Dist: python-dotenv>=1.2.2
14
+ Requires-Dist: requests>=2.31.0
15
+ Description-Content-Type: text/markdown
16
+
1
17
  # Smart Batching Search
2
18
 
3
19
  A high-performance semantic search system that reduces API queries by **67-99%** (varies by topic specificity) through intelligent company grouping and parallel execution.
@@ -267,6 +283,8 @@ Step 2: EXECUTION
267
283
  3. Optionally performs a **second pass**, removing already-retrieved entities from each basket and re-querying for the remainder.
268
284
  4. Enriches each chunk with `entity_ids` and `primary_entity_id`, and returns the raw documents.
269
285
 
286
+ Every search request is sent with `response_detail: "extended"`, so each document includes its filer in `reporting_entity` (a list of entity IDs). The filer is used as a chunk's `entity_ids` when the chunk has no detections, and the second pass counts it as an entity already retrieved.
287
+
270
288
  ## API Reference
271
289
 
272
290
  ### `plan_search()`
@@ -308,7 +326,8 @@ Step 2: EXECUTION
308
326
  ### Helper Functions
309
327
 
310
328
  - `deduplicate_documents(documents)` -- merge duplicate documents by `id`, combining their chunks.
311
- - `convert_to_dataframe(raw_results)` -- convert documents to a DataFrame with one row per chunk.
329
+ - `convert_to_dataframe(raw_results)` -- convert documents to a DataFrame with one row per chunk. The `reporting_entities` column holds the document's filer ids.
330
+ - `get_reporting_entities(document)` -- return the filer ids of a search document (`reporting_entity`; the legacy `reporting_entities` / `reportingEntities` keys are also accepted).
312
331
  - `resolve_universe(universe)` -- load entity IDs from a CSV path or validate a `list[str]`.
313
332
  - `load_universe_from_csv(csv_path)` -- load entity IDs from a CSV only.
314
333
  - `save_plan(plan, path)` / `load_plan(path)` -- persist plans as JSON.
@@ -1,19 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: bigdata-smart-batching
3
- Version: 1.4.1
4
- Summary: High-performance semantic search with intelligent company grouping and parallel execution
5
- Project-URL: homepage, https://bigdata.com/api
6
- Author-email: "Bigdata.com" <support@ravenpack.com>
7
- License: MIT
8
- License-File: LICENSE
9
- Requires-Python: <4.0,>=3.11
10
- Requires-Dist: matplotlib>=3.7
11
- Requires-Dist: numpy>=1.24
12
- Requires-Dist: pandas>=2.0
13
- Requires-Dist: python-dotenv>=1.2.2
14
- Requires-Dist: requests>=2.31.0
15
- Description-Content-Type: text/markdown
16
-
17
1
  # Smart Batching Search
18
2
 
19
3
  A high-performance semantic search system that reduces API queries by **67-99%** (varies by topic specificity) through intelligent company grouping and parallel execution.
@@ -283,6 +267,8 @@ Step 2: EXECUTION
283
267
  3. Optionally performs a **second pass**, removing already-retrieved entities from each basket and re-querying for the remainder.
284
268
  4. Enriches each chunk with `entity_ids` and `primary_entity_id`, and returns the raw documents.
285
269
 
270
+ Every search request is sent with `response_detail: "extended"`, so each document includes its filer in `reporting_entity` (a list of entity IDs). The filer is used as a chunk's `entity_ids` when the chunk has no detections, and the second pass counts it as an entity already retrieved.
271
+
286
272
  ## API Reference
287
273
 
288
274
  ### `plan_search()`
@@ -324,7 +310,8 @@ Step 2: EXECUTION
324
310
  ### Helper Functions
325
311
 
326
312
  - `deduplicate_documents(documents)` -- merge duplicate documents by `id`, combining their chunks.
327
- - `convert_to_dataframe(raw_results)` -- convert documents to a DataFrame with one row per chunk.
313
+ - `convert_to_dataframe(raw_results)` -- convert documents to a DataFrame with one row per chunk. The `reporting_entities` column holds the document's filer ids.
314
+ - `get_reporting_entities(document)` -- return the filer ids of a search document (`reporting_entity`; the legacy `reporting_entities` / `reportingEntities` keys are also accepted).
328
315
  - `resolve_universe(universe)` -- load entity IDs from a CSV path or validate a `list[str]`.
329
316
  - `load_universe_from_csv(csv_path)` -- load entity IDs from a CSV only.
330
317
  - `save_plan(plan, path)` / `load_plan(path)` -- persist plans as JSON.
@@ -70,28 +70,28 @@ def main() -> None:
70
70
  print(f"% overlapping chunks: {(len(merged[merged._merge!='both'])/2)/len(merged)*100:.2f}%")
71
71
  print('a')
72
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
- )
73
+ if False:
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
89
 
90
90
  # Store the results in a file but in parquet format
91
91
  import json
92
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")
93
+ #df = pd.DataFrame(results_raw)
94
+ #df.to_parquet(f"results_raw_{time.time()}_100pct_basket_6_without_sentiment.parquet")
95
95
 
96
96
  plans = []
97
97
  results_dfs = []
@@ -99,7 +99,7 @@ def main() -> None:
99
99
  # Step 1: Plan the search
100
100
  # Try to get plan from file
101
101
  plan_t0 = time.perf_counter()
102
- if False or Path("plan.json").is_file():
102
+ if False: #or Path("plan.json").is_file():
103
103
  plan = load_plan("plan.json")
104
104
  else:
105
105
  plan = plan_search(
@@ -136,6 +136,8 @@ def main() -> None:
136
136
  chunk_percentage=0.1,
137
137
  requests_per_minute=450,
138
138
  )
139
+ df = convert_to_dataframe(results_raw)
140
+ df.to_csv('example_out.csv',index=False)
139
141
  search_elapsed_s = time.perf_counter() - search_t0
140
142
  print(f"Search execution time: {search_elapsed_s:.3f}s")
141
143
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "bigdata-smart-batching"
3
- version = "1.4.1"
3
+ version = "1.5.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" }]
@@ -29,6 +29,14 @@ build-backend = "hatchling.build"
29
29
  [tool.hatch.build.targets.wheel]
30
30
  packages = ["src/bigdata_smart_batching"]
31
31
 
32
+ # Explicit allow-list: never ship untracked local files (.env, notes, scratch examples).
33
+ # Hatchling always adds pyproject.toml, README.md, LICENSE and .gitignore.
34
+ [tool.hatch.build.targets.sdist]
35
+ include = [
36
+ "src/",
37
+ "examples/example.py",
38
+ ]
39
+
32
40
  [project.urls]
33
41
  homepage = "https://bigdata.com/api"
34
42
 
@@ -24,6 +24,7 @@ from .search_function import (
24
24
  build_volume_payload,
25
25
  deduplicate_documents,
26
26
  execute_search,
27
+ get_reporting_entities,
27
28
  load_plan,
28
29
  load_universe_from_csv,
29
30
  plan_search,
@@ -51,6 +52,7 @@ __all__ = [
51
52
  "convert_to_dataframe",
52
53
  "deduplicate_documents",
53
54
  "execute_search",
55
+ "get_reporting_entities",
54
56
  "load_plan",
55
57
  "load_universe_from_csv",
56
58
  "plan_search",
@@ -1,5 +1,7 @@
1
1
  import pandas as pd
2
2
 
3
+ from .search_function import get_reporting_entities
4
+
3
5
 
4
6
  def convert_to_dataframe(raw_results: list[dict]) -> pd.DataFrame:
5
7
  """
@@ -25,7 +27,7 @@ def convert_to_dataframe(raw_results: list[dict]) -> pd.DataFrame:
25
27
  headline = raw_doc.get("headline", "")
26
28
  timestamp = raw_doc.get("timestamp", "")
27
29
  url = raw_doc.get("url", "")
28
- reporting_entities = raw_doc.get("reporting_entities", [])
30
+ reporting_entities = get_reporting_entities(raw_doc)
29
31
 
30
32
  # Extract source info
31
33
  raw_source = raw_doc.get("source", {})
@@ -42,6 +42,8 @@ logger = logging.getLogger(__name__)
42
42
  DEFAULT_API_BASE_URL = os.getenv("BIGDATA_API_BASE_URL", "https://api.bigdata.com")
43
43
  SEARCH_ENDPOINT = "/v1/search"
44
44
  COMENTION_ENDPOINT = "/v1/search/co-mentions/entities"
45
+ # Only "extended" returns the filer (``reporting_entity``). Bigdata API change of 2026-10-22.
46
+ SEARCH_RESPONSE_DETAIL = "extended"
45
47
  MAX_ENTITIES_IN_ANY_OF = 500
46
48
  MAX_CHUNKS_PER_BASKET = 1000
47
49
  DEFAULT_REQUESTS_PER_MINUTE = int(os.getenv("BIGDATA_REQUESTS_PER_MINUTE", "450"))
@@ -1114,6 +1116,22 @@ def exponential_backoff(
1114
1116
  return max(0.0, min(delay, cap))
1115
1117
 
1116
1118
 
1119
+ def get_reporting_entities(document: dict) -> list[str]:
1120
+ """Filer ids of a /v1/search document.
1121
+
1122
+ The API returns them as ``reporting_entity`` (a list) only with
1123
+ ``response_detail="extended"`` (since 2026-10-22). The legacy plural keys
1124
+ ``reporting_entities`` / ``reportingEntities`` are still accepted.
1125
+ """
1126
+ value = (
1127
+ document.get("reporting_entity")
1128
+ or document.get("reporting_entities")
1129
+ or document.get("reportingEntities")
1130
+ or []
1131
+ )
1132
+ return [e for e in (value if isinstance(value, list) else [value]) if e]
1133
+
1134
+
1117
1135
  def make_search_request(
1118
1136
  query: dict,
1119
1137
  api_key: str,
@@ -1125,6 +1143,9 @@ def make_search_request(
1125
1143
  """
1126
1144
  Make a search API request with rate limiting and retry logic.
1127
1145
 
1146
+ Always sends ``response_detail="extended"`` at the top level of the body
1147
+ (next to ``query``, not inside it) so documents include ``reporting_entity``.
1148
+
1128
1149
  Args:
1129
1150
  query: Complete query structure
1130
1151
  api_key: API key
@@ -1139,7 +1160,7 @@ def make_search_request(
1139
1160
  url = f"{api_base_url}{SEARCH_ENDPOINT}"
1140
1161
  headers = {"X-API-KEY": api_key, "Content-Type": "application/json"}
1141
1162
 
1142
- payload = {"query": query}
1163
+ payload = {"query": query, "response_detail": SEARCH_RESPONSE_DETAIL}
1143
1164
 
1144
1165
  retry_count = 0
1145
1166
  while retry_count < max_retries:
@@ -1368,12 +1389,8 @@ def execute_search(
1368
1389
  for document in documents:
1369
1390
  document_chunks = document.get("chunks", [])
1370
1391
  total_chunks += len(document_chunks)
1371
- # Get document-level entity information (try both snake_case and camelCase)
1372
- reporting_entities = (
1373
- document.get("reporting_entities")
1374
- or document.get("reportingEntities")
1375
- or []
1376
- )
1392
+ # Document-level filer ids (reporting_entity)
1393
+ reporting_entities = get_reporting_entities(document)
1377
1394
 
1378
1395
  # Debug: Log first document and chunk structure
1379
1396
  if not first_doc_logged and document_chunks:
@@ -1418,12 +1435,9 @@ def execute_search(
1418
1435
  if entity_id:
1419
1436
  entity_ids.append(entity_id)
1420
1437
 
1421
- # Try document-level reporting_entities
1438
+ # Fall back to the document's filer (reporting_entity)
1422
1439
  if not entity_ids and reporting_entities:
1423
- if isinstance(reporting_entities, list):
1424
- entity_ids = [e for e in reporting_entities if e]
1425
- else:
1426
- entity_ids = [reporting_entities] if reporting_entities else []
1440
+ entity_ids = list(reporting_entities)
1427
1441
 
1428
1442
  # Store entity information (always set, even if empty)
1429
1443
  if basket_filtered_entities:
@@ -1503,7 +1517,7 @@ def execute_search(
1503
1517
  for chunk in i.get("chunks", [])
1504
1518
  for entity in chunk.get("entity_ids", [])
1505
1519
  ]
1506
- + [entity for i in all_documents for entity in i.get("reporting_entities", [])]
1520
+ + [entity for i in all_documents for entity in get_reporting_entities(i)]
1507
1521
  + [
1508
1522
  chunk.get("primary_entity_id")
1509
1523
  for i in all_documents
@@ -1,165 +0,0 @@
1
- # Changelog
2
-
3
- All notable changes to this project are documented in this file.
4
-
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
-
8
-
9
- ## [1.4.1] - 2026-06-02
10
-
11
- ### Fixed
12
-
13
- - `SmartBatchingPlanner._post_with_retry`: retry with exponential backoff on any non-200 HTTP status or transient network error. Previously only `429` and `403` were retried; other statuses (e.g. `500`) failed immediately.
14
-
15
- ## [1.4.0] - 2026-05-20
16
-
17
- ### Added
18
-
19
- - `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.
20
-
21
- ## [1.3.1] - 2026-05-19
22
-
23
- ### Fixed
24
-
25
- - Now we always retry requests, before we were only retrying on 429 and 403 errors.
26
-
27
- ## [1.3.0] - 2026-05-12
28
-
29
- ### Added
30
-
31
- - 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.
32
-
33
- ## [1.2.1] - 2026-05-12
34
-
35
- ### Fixed
36
-
37
- - Modified README.md file to add latest changes
38
-
39
- ## [1.2.0] - 2026-05-12
40
-
41
- ### Added
42
-
43
- - Document-level **sentiment** filters: inclusive `min` / `max` range(s), validated with `validate_sentiment_range`, modeled as `SentimentRange` / `SentimentRangeInput`, serialized to `query.filters.sentiment.ranges` on co-mention, volume, and search payloads. `plan_search(..., sentiment=...)` and `sentiment_filter` plumbed through `SmartBatchingPlanner` co-mention and volume flows. Types and validator re-exported from the package root.
44
- - **Planning throughput controls**: `plan_search(..., requests_per_minute=..., max_workers=...)` and `SmartBatchingPlanner(..., requests_per_minute=..., max_workers=..., rate_limiter=..., concurrency_limiter=...)` so all planner HTTP work shares one sliding-window rate limiter and one concurrency semaphore across internal thread pools.
45
- - **`exponential_backoff`** helper in `search_function` (used by retry paths; capped via `MAX_RETRY_BACKOFF_SECONDS`).
46
-
47
- ### Changed
48
-
49
- - **Retries:** co-mention / volume POST retries now use **shared exponential backoff** for `429`, `403`, timeouts, and other failures, instead of parsing `Retry-After` for `429` and separate ad-hoc `403` handling (constant renamed/clamped to `MAX_RETRY_BACKOFF_SECONDS`).
50
- - **Volume time-series merge:** when aggregating batch results per date, a **`sentiment`** value on each point is the arithmetic mean of batch sentiments for that date (batches without sentiment for that date are omitted from the mean).
51
- - **`SlidingWindowRateLimiter`:** window accounting aligned with **ceil-based** `max_per_window` expectations (tests updated for low rates and 450 rpm-style cases).
52
-
53
-
54
-
55
- ## [1.1.0] - 2026-04-20
56
-
57
- ### Added
58
-
59
- - `convert_to_dataframe` now includes a `detections` column: for each chunk row,
60
- entity detections are taken from `chunk["detections"]` (entries with
61
- `type == "entity"`); rows without chunks use an empty list.
62
-
63
- ## [1.0.2] - 2026-04-17
64
-
65
- ### Fixed
66
-
67
- - Corrected README file
68
-
69
- ## [1.0.1] - 2026-04-17
70
-
71
- ### Fixed
72
-
73
- - Republish on PyPI after an erroneous publish of v1.0.0; package contents match the intended release.
74
-
75
-
76
- ## [1.0.0] - 2026-04-17
77
-
78
- First stable release. Redesigns the batching pipeline so every API request stays
79
- within service limits while keeping plans deterministic.
80
-
81
- ### Added
82
-
83
- - `create_entity_groups` step: sorts companies by chunks desc and greedy-packs
84
- under `MAX_CHUNKS_PER_BASKET` and `MAX_ENTITIES_IN_ANY_OF`, honoring
85
- `min_entities_per_basket`, with tail-group merge when it fits the entity
86
- limit.
87
- - Automatic splitting of co-mention volume queries into sub-ranges of up to 365
88
- days, with per-company chunks summed across sub-ranges in both three-pass and
89
- iterative modes. Iterative mode now fans out `(batch, sub-range)` work items
90
- to the thread pool and derives `very_low` from companies never seen in any
91
- sub-range.
92
- - Parallel execution of `get_volume_timeseries` via `ThreadPoolExecutor`.
93
- - `volume_bucket` metadata on every group/basket via `classify_volume_bucket`
94
- and `majority_volume_bucket` (ties broken by `VOLUME_BUCKET_PRIORITY`).
95
- - Centralized `VOLUME_BUCKETS` in `smart_batching_config` with explicit
96
- `[lower, upper)` semantics and new `VOLUME_BUCKET_PRIORITY` constant.
97
- - INCLUDE/EXCLUDE category filtering for planning and all Bigdata query paths
98
- (co-mention, volume, search), validated against a fixed set of allowed
99
- category strings. `CategoryFilter`, `CategoryMode`, and validators/builders
100
- are exported from the package.
101
- - Shared payload builders `build_comention_payload`, `build_volume_payload`,
102
- and `build_search_query`, which `SmartBatchingPlanner` now routes through
103
- instead of constructing payloads inline.
104
- - `content_diversification` option in `ranking_params`, exposed on
105
- `plan_search`.
106
- - Universe input accepts either a CSV path or an inline list of entity IDs
107
- (`universe: str | list[str]`). Added `resolve_universe()` and `UniverseInput`,
108
- both exported from the package.
109
- - `Makefile` test targets and coverage settings in `pyproject.toml`.
110
-
111
- ### Changed
112
-
113
- - **Breaking:** `SmartBatchingPlanner` public API redesigned. `create_baskets`
114
- is replaced by `create_entity_groups` (new signature:
115
- `min_entities_per_group` instead of `max_chunks`/`min_entities_per_basket`);
116
- returned dicts no longer include `basket_id` or `volume_range` and expose
117
- `volume_bucket` instead.
118
- - **Breaking:** Removed helpers `group_by_volume`,
119
- `consolidate_period_groups`, `sub_period_volumes_from_series`, and
120
- `get_volume_timeseries_per_company`.
121
- - **Breaking:** `very_low` basket IDs are now
122
- `basket_{n}_very_low_{start}_{end}` instead of `very_low_basket_{n}`;
123
- downstream parsers must be updated.
124
- - **Breaking:** `VOLUME_BUCKETS` ranges are now enforced as `[lower, upper)`.
125
- - **Breaking:** `plan_search(..., universe_csv_path=)` renamed to
126
- `universe=` (accepts `str | list[str]`). `SmartBatchingPlanner.load_universe`
127
- and `plan_all_periods` now take a required `universe` argument and delegate
128
- to `resolve_universe`; `UNIVERSE_CSV_PATH` and duplicate CSV parsing removed.
129
- - **Breaking:** `plan_search` / `plan_all_periods` now accept an optional
130
- `text` parameter and parameter order has been reordered.
131
- - Entity filters now use `search_in=BODY` for co-mention and volume payloads;
132
- `ranking_params` dropped from the volume query.
133
- - Omit `text` from co-mention, volume, and search payloads when topic/text is
134
- `None`.
135
- - Planned baskets are sorted by `basket_id` for stable ordering.
136
- - Architecture documentation updated to reflect the new `plan_search` flow
137
- (sub-range splitting, entity groups, pre-fetch only for heavy groups, one
138
- basket per `(group, sub-period)`) and a new high-level flow diagram.
139
- - `load_universe_from_csv` rejects empty CSV paths.
140
-
141
- ### Removed
142
-
143
- - Obsolete `VOLUME_BUCKETS` structure test.
144
-
145
- ## [0.2.0] - 2026-04-14
146
-
147
- ### Changed
148
-
149
- - **Breaking:** `plan_search` now returns `chunk_upper_bound_estimate` instead of `total_expected_chunks`. Callers, saved plans, and any code reading the plan dict must use the new key. `execute_search` reads `chunk_upper_bound_estimate` when deriving sampling from the plan.
150
- - Terminology and docs describe this value as a chunk upper bound estimate (module docstring, README, architecture diagram, and example output).
151
- - README installation: document PyPI consumption (`pip install bigdata-smart-batching`, `uv add bigdata-smart-batching`) and keep a separate **Development** section for cloning the repo and `uv sync`.
152
-
153
- ### Fixed
154
-
155
- - Align `uv.lock` `requires-python` with `pyproject.toml` (`>=3.11,<4.0`).
156
-
157
- ## [0.1.0] - 2026-04-14
158
-
159
- ### Added
160
-
161
- - Initial release of **bigdata-smart-batching**: high-performance semantic search with intelligent company grouping and parallel execution.
162
- - Planning API (`plan_search`) to organize searches via smart batching and report expected chunk counts.
163
- - Execution API (`execute_search`) with rate-limited parallel requests and proportional sampling to preserve result distribution.
164
- - Utilities: document deduplication, DataFrame conversion, and configurable search/batching behavior via `smart_batching` and related modules.
165
- - Python 3.11+ support; dependencies include `requests`, `pandas`, `numpy`, `matplotlib`, and `python-dotenv`.
@@ -1,19 +0,0 @@
1
- .PHONY: lint lint-check format format-check test test-cov
2
-
3
- lint:
4
- uvx ruff check --fix src/ tests/
5
-
6
- lint-check:
7
- uvx ruff check --extend-select I src/ tests/
8
-
9
- format:
10
- uvx ruff format src/ tests/
11
-
12
- format-check:
13
- uvx ruff format --check src/ tests/
14
-
15
- test:
16
- uv run pytest
17
-
18
- test-cov:
19
- uv run pytest --cov --cov-report=term-missing --cov-report=html