bigdata-smart-batching 1.2.0__tar.gz → 1.3.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.2.0 → bigdata_smart_batching-1.3.0}/CHANGELOG.md +12 -0
  2. {bigdata_smart_batching-1.2.0 → bigdata_smart_batching-1.3.0}/PKG-INFO +89 -3
  3. {bigdata_smart_batching-1.2.0 → bigdata_smart_batching-1.3.0}/README.md +88 -2
  4. {bigdata_smart_batching-1.2.0 → bigdata_smart_batching-1.3.0}/examples/example.py +4 -3
  5. bigdata_smart_batching-1.3.0/plan.json +20473 -0
  6. {bigdata_smart_batching-1.2.0 → bigdata_smart_batching-1.3.0}/pyproject.toml +1 -1
  7. {bigdata_smart_batching-1.2.0 → bigdata_smart_batching-1.3.0}/src/bigdata_smart_batching/__init__.py +8 -0
  8. {bigdata_smart_batching-1.2.0 → bigdata_smart_batching-1.3.0}/src/bigdata_smart_batching/search_function.py +94 -0
  9. {bigdata_smart_batching-1.2.0 → bigdata_smart_batching-1.3.0}/src/bigdata_smart_batching/smart_batching.py +23 -0
  10. {bigdata_smart_batching-1.2.0 → bigdata_smart_batching-1.3.0}/tests/test_validation.py +63 -0
  11. {bigdata_smart_batching-1.2.0 → bigdata_smart_batching-1.3.0}/uv.lock +1 -1
  12. {bigdata_smart_batching-1.2.0 → bigdata_smart_batching-1.3.0}/.gitignore +0 -0
  13. {bigdata_smart_batching-1.2.0 → bigdata_smart_batching-1.3.0}/LICENSE +0 -0
  14. {bigdata_smart_batching-1.2.0 → bigdata_smart_batching-1.3.0}/Makefile +0 -0
  15. {bigdata_smart_batching-1.2.0 → bigdata_smart_batching-1.3.0}/docs/smart-batching-architecture.md +0 -0
  16. {bigdata_smart_batching-1.2.0 → bigdata_smart_batching-1.3.0}/examples/example_overlapping.py +0 -0
  17. {bigdata_smart_batching-1.2.0 → bigdata_smart_batching-1.3.0}/src/bigdata_smart_batching/output_converter.py +0 -0
  18. {bigdata_smart_batching-1.2.0 → bigdata_smart_batching-1.3.0}/src/bigdata_smart_batching/smart_batching_config.py +0 -0
  19. {bigdata_smart_batching-1.2.0 → bigdata_smart_batching-1.3.0}/tests/__init__.py +0 -0
  20. {bigdata_smart_batching-1.2.0 → bigdata_smart_batching-1.3.0}/tests/test_config.py +0 -0
  21. {bigdata_smart_batching-1.2.0 → bigdata_smart_batching-1.3.0}/tests/test_output_converter.py +0 -0
  22. {bigdata_smart_batching-1.2.0 → bigdata_smart_batching-1.3.0}/tests/test_rate_limiter.py +0 -0
@@ -5,6 +5,18 @@ All notable changes to this project are documented in this file.
5
5
  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
+ ## [1.3.0] - 2026-05-12
9
+
10
+ ### Added
11
+
12
+ - 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
+
14
+ ## [1.2.1] - 2026-05-12
15
+
16
+ ### Fixed
17
+
18
+ - Modified README.md file to add latest changes
19
+
8
20
  ## [1.2.0] - 2026-05-12
9
21
 
10
22
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bigdata-smart-batching
3
- Version: 1.2.0
3
+ Version: 1.3.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>
@@ -29,6 +29,9 @@ This module provides a two-step pipeline for efficient semantic search:
29
29
  - **Parallel execution** -- rate-limited concurrent requests with semaphore-controlled concurrency.
30
30
  - **Proportional sampling** -- retrieve a percentage of results while preserving the distribution across baskets.
31
31
  - **Category filtering** -- restrict searches to specific document categories (news, transcripts, filings, ...).
32
+ - **Source filtering** -- include or exclude documents by source identifiers (`INCLUDE` / `EXCLUDE` plus a list of source IDs).
33
+ - **Sentiment filtering** -- restrict searches to one or more inclusive document-level sentiment ranges.
34
+ - **Throughput controls** -- shared sliding-window rate limiter and concurrency semaphore across all planning HTTP work, with shared exponential backoff on `429` / `403` / timeout retries.
32
35
  - **Deterministic plans** -- every request stays within service limits; plans can be saved and replayed.
33
36
  - **Scalable** -- handles universes with 10,000+ companies efficiently.
34
37
 
@@ -162,6 +165,78 @@ Valid category values are exposed via `VALID_CATEGORY_VALUES` and include:
162
165
  `news_public`, `podcasts`, `research`, `research_academic_journals`,
163
166
  `research_investment_research`, `transcripts`.
164
167
 
168
+ ### Source Filtering
169
+
170
+ Restrict searches by **source** (document source IDs) using the `source` argument.
171
+ It accepts either a `SourceFilter` dataclass or a plain dict with `mode`
172
+ (`INCLUDE` or `EXCLUDE`) and `values` (a non-empty list of source ID strings).
173
+ The filter is serialized to `query.filters.source` on co-mention, volume, and
174
+ search payloads during planning.
175
+
176
+ ```python
177
+ from bigdata_smart_batching import SourceFilter, SourceMode, plan_search
178
+
179
+ plan = plan_search(
180
+ universe="id_name_mapping_us_top_3000.csv",
181
+ start_date="2023-01-01",
182
+ end_date="2023-12-31",
183
+ text="merger acquisition",
184
+ source=SourceFilter(
185
+ mode=SourceMode.INCLUDE,
186
+ values=("source-id-1", "source-id-2"),
187
+ ),
188
+ )
189
+
190
+ # Equivalent dict form:
191
+ plan = plan_search(
192
+ universe="id_name_mapping_us_top_3000.csv",
193
+ start_date="2023-01-01",
194
+ end_date="2023-12-31",
195
+ text="merger acquisition",
196
+ source={"mode": "EXCLUDE", "values": ["source-id-to-drop"]},
197
+ )
198
+ ```
199
+
200
+ `SourceMode` is the same `INCLUDE` / `EXCLUDE` enum as `CategoryMode`. String
201
+ values are trimmed; empty strings are rejected. Use
202
+ `validate_source_filter(source)` to validate and normalize input into the API
203
+ dict shape.
204
+
205
+ ### Sentiment Filtering
206
+
207
+ Restrict searches to documents whose sentiment falls inside one or more
208
+ inclusive `min` / `max` ranges using the `sentiment` argument. It accepts a
209
+ single `SentimentRange` / dict, or a list of them (multiple disjoint ranges).
210
+ The filter is emitted as `query.filters.sentiment.ranges` on co-mention,
211
+ volume, and search payloads.
212
+
213
+ ```python
214
+ from bigdata_smart_batching import SentimentRange, plan_search
215
+
216
+ plan = plan_search(
217
+ universe="id_name_mapping_us_top_3000.csv",
218
+ start_date="2023-01-01",
219
+ end_date="2023-12-31",
220
+ text="earnings revenue profit",
221
+ sentiment=SentimentRange(min=0.3, max=1.0),
222
+ )
223
+
224
+ plan = plan_search(
225
+ universe="id_name_mapping_us_top_3000.csv",
226
+ start_date="2023-01-01",
227
+ end_date="2023-12-31",
228
+ text="earnings revenue profit",
229
+ sentiment=[
230
+ {"min": -1.0, "max": -0.5},
231
+ {"min": 0.5, "max": 1.0},
232
+ ],
233
+ )
234
+ ```
235
+
236
+ Each range must satisfy `min <= max`. Use
237
+ `validate_sentiment_range(sentiment)` to validate and normalize input into the
238
+ list-of-dicts shape the API expects.
239
+
165
240
  ### Save and Load Plans
166
241
 
167
242
  ```python
@@ -226,7 +301,11 @@ Step 2: EXECUTION
226
301
  | `min_period_days` | `int` | `30` | Minimum days per sub-period |
227
302
  | `min_entities_per_basket` | `int` | `1` | Lower bound on entities per basket |
228
303
  | `category` | `CategoryFilter \| dict \| None` | `None` | Optional category filter (`mode` + `values`) |
304
+ | `source` | `SourceFilter \| dict \| None` | `None` | Optional source filter by source IDs (`mode` + `values`) |
305
+ | `sentiment` | `SentimentRange \| dict \| list \| None` | `None` | Optional sentiment filter: one inclusive `{min, max}` range or a list of disjoint ranges |
229
306
  | `content_diversification` | `bool` | `True` | Enable/disable content diversification in ranking |
307
+ | `requests_per_minute` | `int` | `100` | Global rate limit shared across all planning HTTP work (co-mention + volume) |
308
+ | `max_workers` | `int` | `40` | Maximum concurrent in-flight planning requests (shared semaphore) |
230
309
 
231
310
  ### `execute_search()`
232
311
 
@@ -249,13 +328,20 @@ Step 2: EXECUTION
249
328
  - `load_universe_from_csv(csv_path)` -- load entity IDs from a CSV only.
250
329
  - `save_plan(plan, path)` / `load_plan(path)` -- persist plans as JSON.
251
330
  - `validate_category_filter(category)` -- validate and normalize a category filter to the API dict shape.
252
- - `build_comention_payload(...)`, `build_volume_payload(...)`, `build_search_query(...)` -- low-level payload builders used by the planner; useful if you need to construct custom requests.
331
+ - `validate_source_filter(source)` -- validate and normalize a source filter to the API dict shape (`filters.source`).
332
+ - `validate_sentiment_range(sentiment)` -- validate and normalize sentiment range(s) into the list-of-`{min, max}` dicts emitted as `filters.sentiment.ranges`.
333
+ - `build_comention_payload(...)`, `build_volume_payload(...)`, `build_search_query(...)` -- low-level payload builders used by the planner; each accepts optional `category_filter`, `source_filter`, and `sentiment_filter` alongside entities and dates. Useful if you need to construct custom requests.
253
334
 
254
335
  ### Public Types
255
336
 
256
337
  - `CategoryFilter` -- frozen dataclass with `mode: CategoryMode` and `values: tuple[str, ...]`.
257
338
  - `CategoryMode` -- `StrEnum` with `INCLUDE` and `EXCLUDE` values.
258
339
  - `CategoryFilterInput` -- type alias: `CategoryFilter | dict[str, str | list[str]]`.
340
+ - `SourceFilter` -- frozen dataclass with `mode: SourceMode` and `values: tuple[str, ...]` (source IDs).
341
+ - `SourceMode` -- type alias of `CategoryMode` (`INCLUDE`, `EXCLUDE`).
342
+ - `SourceFilterInput` -- type alias: `SourceFilter | dict[str, str | list[str]]`.
343
+ - `SentimentRange` -- frozen dataclass with inclusive `min: float` and `max: float`.
344
+ - `SentimentRangeInput` -- type alias for one `SentimentRange` / `{min, max}` dict, or a non-empty list of either.
259
345
  - `UniverseInput` -- type alias: `str | list[str]`.
260
346
  - `VALID_CATEGORY_VALUES` -- `frozenset[str]` of allowed category strings.
261
347
 
@@ -331,7 +417,7 @@ Ties are resolved using `VOLUME_BUCKET_PRIORITY`: `high > medium > low > very_lo
331
417
  ## Changelog
332
418
 
333
419
  See [CHANGELOG.md](CHANGELOG.md) for release notes. The package is currently at
334
- version **1.0.1**.
420
+ version **1.2.0**.
335
421
 
336
422
  ## License
337
423
 
@@ -13,6 +13,9 @@ This module provides a two-step pipeline for efficient semantic search:
13
13
  - **Parallel execution** -- rate-limited concurrent requests with semaphore-controlled concurrency.
14
14
  - **Proportional sampling** -- retrieve a percentage of results while preserving the distribution across baskets.
15
15
  - **Category filtering** -- restrict searches to specific document categories (news, transcripts, filings, ...).
16
+ - **Source filtering** -- include or exclude documents by source identifiers (`INCLUDE` / `EXCLUDE` plus a list of source IDs).
17
+ - **Sentiment filtering** -- restrict searches to one or more inclusive document-level sentiment ranges.
18
+ - **Throughput controls** -- shared sliding-window rate limiter and concurrency semaphore across all planning HTTP work, with shared exponential backoff on `429` / `403` / timeout retries.
16
19
  - **Deterministic plans** -- every request stays within service limits; plans can be saved and replayed.
17
20
  - **Scalable** -- handles universes with 10,000+ companies efficiently.
18
21
 
@@ -146,6 +149,78 @@ Valid category values are exposed via `VALID_CATEGORY_VALUES` and include:
146
149
  `news_public`, `podcasts`, `research`, `research_academic_journals`,
147
150
  `research_investment_research`, `transcripts`.
148
151
 
152
+ ### Source Filtering
153
+
154
+ Restrict searches by **source** (document source IDs) using the `source` argument.
155
+ It accepts either a `SourceFilter` dataclass or a plain dict with `mode`
156
+ (`INCLUDE` or `EXCLUDE`) and `values` (a non-empty list of source ID strings).
157
+ The filter is serialized to `query.filters.source` on co-mention, volume, and
158
+ search payloads during planning.
159
+
160
+ ```python
161
+ from bigdata_smart_batching import SourceFilter, SourceMode, plan_search
162
+
163
+ plan = plan_search(
164
+ universe="id_name_mapping_us_top_3000.csv",
165
+ start_date="2023-01-01",
166
+ end_date="2023-12-31",
167
+ text="merger acquisition",
168
+ source=SourceFilter(
169
+ mode=SourceMode.INCLUDE,
170
+ values=("source-id-1", "source-id-2"),
171
+ ),
172
+ )
173
+
174
+ # Equivalent dict form:
175
+ plan = plan_search(
176
+ universe="id_name_mapping_us_top_3000.csv",
177
+ start_date="2023-01-01",
178
+ end_date="2023-12-31",
179
+ text="merger acquisition",
180
+ source={"mode": "EXCLUDE", "values": ["source-id-to-drop"]},
181
+ )
182
+ ```
183
+
184
+ `SourceMode` is the same `INCLUDE` / `EXCLUDE` enum as `CategoryMode`. String
185
+ values are trimmed; empty strings are rejected. Use
186
+ `validate_source_filter(source)` to validate and normalize input into the API
187
+ dict shape.
188
+
189
+ ### Sentiment Filtering
190
+
191
+ Restrict searches to documents whose sentiment falls inside one or more
192
+ inclusive `min` / `max` ranges using the `sentiment` argument. It accepts a
193
+ single `SentimentRange` / dict, or a list of them (multiple disjoint ranges).
194
+ The filter is emitted as `query.filters.sentiment.ranges` on co-mention,
195
+ volume, and search payloads.
196
+
197
+ ```python
198
+ from bigdata_smart_batching import SentimentRange, plan_search
199
+
200
+ plan = plan_search(
201
+ universe="id_name_mapping_us_top_3000.csv",
202
+ start_date="2023-01-01",
203
+ end_date="2023-12-31",
204
+ text="earnings revenue profit",
205
+ sentiment=SentimentRange(min=0.3, max=1.0),
206
+ )
207
+
208
+ plan = plan_search(
209
+ universe="id_name_mapping_us_top_3000.csv",
210
+ start_date="2023-01-01",
211
+ end_date="2023-12-31",
212
+ text="earnings revenue profit",
213
+ sentiment=[
214
+ {"min": -1.0, "max": -0.5},
215
+ {"min": 0.5, "max": 1.0},
216
+ ],
217
+ )
218
+ ```
219
+
220
+ Each range must satisfy `min <= max`. Use
221
+ `validate_sentiment_range(sentiment)` to validate and normalize input into the
222
+ list-of-dicts shape the API expects.
223
+
149
224
  ### Save and Load Plans
150
225
 
151
226
  ```python
@@ -210,7 +285,11 @@ Step 2: EXECUTION
210
285
  | `min_period_days` | `int` | `30` | Minimum days per sub-period |
211
286
  | `min_entities_per_basket` | `int` | `1` | Lower bound on entities per basket |
212
287
  | `category` | `CategoryFilter \| dict \| None` | `None` | Optional category filter (`mode` + `values`) |
288
+ | `source` | `SourceFilter \| dict \| None` | `None` | Optional source filter by source IDs (`mode` + `values`) |
289
+ | `sentiment` | `SentimentRange \| dict \| list \| None` | `None` | Optional sentiment filter: one inclusive `{min, max}` range or a list of disjoint ranges |
213
290
  | `content_diversification` | `bool` | `True` | Enable/disable content diversification in ranking |
291
+ | `requests_per_minute` | `int` | `100` | Global rate limit shared across all planning HTTP work (co-mention + volume) |
292
+ | `max_workers` | `int` | `40` | Maximum concurrent in-flight planning requests (shared semaphore) |
214
293
 
215
294
  ### `execute_search()`
216
295
 
@@ -233,13 +312,20 @@ Step 2: EXECUTION
233
312
  - `load_universe_from_csv(csv_path)` -- load entity IDs from a CSV only.
234
313
  - `save_plan(plan, path)` / `load_plan(path)` -- persist plans as JSON.
235
314
  - `validate_category_filter(category)` -- validate and normalize a category filter to the API dict shape.
236
- - `build_comention_payload(...)`, `build_volume_payload(...)`, `build_search_query(...)` -- low-level payload builders used by the planner; useful if you need to construct custom requests.
315
+ - `validate_source_filter(source)` -- validate and normalize a source filter to the API dict shape (`filters.source`).
316
+ - `validate_sentiment_range(sentiment)` -- validate and normalize sentiment range(s) into the list-of-`{min, max}` dicts emitted as `filters.sentiment.ranges`.
317
+ - `build_comention_payload(...)`, `build_volume_payload(...)`, `build_search_query(...)` -- low-level payload builders used by the planner; each accepts optional `category_filter`, `source_filter`, and `sentiment_filter` alongside entities and dates. Useful if you need to construct custom requests.
237
318
 
238
319
  ### Public Types
239
320
 
240
321
  - `CategoryFilter` -- frozen dataclass with `mode: CategoryMode` and `values: tuple[str, ...]`.
241
322
  - `CategoryMode` -- `StrEnum` with `INCLUDE` and `EXCLUDE` values.
242
323
  - `CategoryFilterInput` -- type alias: `CategoryFilter | dict[str, str | list[str]]`.
324
+ - `SourceFilter` -- frozen dataclass with `mode: SourceMode` and `values: tuple[str, ...]` (source IDs).
325
+ - `SourceMode` -- type alias of `CategoryMode` (`INCLUDE`, `EXCLUDE`).
326
+ - `SourceFilterInput` -- type alias: `SourceFilter | dict[str, str | list[str]]`.
327
+ - `SentimentRange` -- frozen dataclass with inclusive `min: float` and `max: float`.
328
+ - `SentimentRangeInput` -- type alias for one `SentimentRange` / `{min, max}` dict, or a non-empty list of either.
243
329
  - `UniverseInput` -- type alias: `str | list[str]`.
244
330
  - `VALID_CATEGORY_VALUES` -- `frozenset[str]` of allowed category strings.
245
331
 
@@ -315,7 +401,7 @@ Ties are resolved using `VOLUME_BUCKET_PRIORITY`: `high > medium > low > very_lo
315
401
  ## Changelog
316
402
 
317
403
  See [CHANGELOG.md](CHANGELOG.md) for release notes. The package is currently at
318
- version **1.0.1**.
404
+ version **1.2.0**.
319
405
 
320
406
  ## License
321
407
 
@@ -67,6 +67,7 @@ def main() -> None:
67
67
  # Optional: filter by category to restrict document sources.
68
68
  # Accepts a CategoryFilter instance or a plain dict:
69
69
  category={"mode": "INCLUDE", "values": ["news_premium"]},
70
+ source={"mode": "INCLUDE", "values": ["5A5702"]},
70
71
  content_diversification=False,
71
72
  sentiment=[{"min": -1, "max": -0.5},{"min": 0.5, "max": 1}],
72
73
  )
@@ -80,12 +81,12 @@ def main() -> None:
80
81
  print(f"Plan execution time: {plan_elapsed_s:.3f}s")
81
82
 
82
83
  # Step 2: Execute search with 10% of total chunks (preserves distribution)
83
- if False:
84
+ if True:
84
85
  search_t0 = time.perf_counter()
85
86
  results_raw = execute_search(
86
87
  search_plan=plan,
87
- chunk_percentage=1,
88
- requests_per_minute=300,
88
+ chunk_percentage=0.1,
89
+ requests_per_minute=450,
89
90
  )
90
91
  search_elapsed_s = time.perf_counter() - search_t0
91
92
  print(f"Search execution time: {search_elapsed_s:.3f}s")