opensolr-haystack 0.2.2__tar.gz → 0.2.4__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opensolr-haystack
3
- Version: 0.2.2
3
+ Version: 0.2.4
4
4
  Summary: Haystack integration for Opensolr — managed Apache Solr DocumentStore with server-side embeddings and hybrid BM25+kNN retrieval
5
5
  Author-email: Opensolr <support@opensolr.com>
6
6
  License: MIT
@@ -136,6 +136,23 @@ answer = store.ai_answer(
136
136
  )
137
137
  ```
138
138
 
139
+
140
+ ### Search tuning
141
+
142
+ Retrieval (search and RAG grounding) runs through the platform's tuned
143
+ pipeline: global defaults → your index's saved **Search Tuning** (Control
144
+ Panel → Index Settings → Search Tuning: semantic↔lexical balance, field
145
+ weights, minimum match, search mode, vector candidate pool, content quality
146
+ boost) → optional per-call overrides via `tuning`:
147
+
148
+ ```
149
+ tuning={"search_mode": "keywords_required", "fw_title": 0.2,
150
+ "mm": "strict", "vector_topk": 500, "quality_boost": 0.3}
151
+ ```
152
+
153
+ Defaults match the platform's PHP configuration exactly — customize in the
154
+ Control Panel once, or per call from code.
155
+
139
156
  ## How it's tested
140
157
 
141
158
  Every release is validated against **live Opensolr infrastructure** — no mocks:
@@ -118,6 +118,23 @@ answer = store.ai_answer(
118
118
  )
119
119
  ```
120
120
 
121
+
122
+ ### Search tuning
123
+
124
+ Retrieval (search and RAG grounding) runs through the platform's tuned
125
+ pipeline: global defaults → your index's saved **Search Tuning** (Control
126
+ Panel → Index Settings → Search Tuning: semantic↔lexical balance, field
127
+ weights, minimum match, search mode, vector candidate pool, content quality
128
+ boost) → optional per-call overrides via `tuning`:
129
+
130
+ ```
131
+ tuning={"search_mode": "keywords_required", "fw_title": 0.2,
132
+ "mm": "strict", "vector_topk": 500, "quality_boost": 0.3}
133
+ ```
134
+
135
+ Defaults match the platform's PHP configuration exactly — customize in the
136
+ Control Panel once, or per call from code.
137
+
121
138
  ## How it's tested
122
139
 
123
140
  Every release is validated against **live Opensolr infrastructure** — no mocks:
@@ -233,7 +233,20 @@ class OpensolrClient:
233
233
  raise OpensolrError(f"ingest_status: non-JSON response: {resp.text[:200]}") from exc
234
234
 
235
235
  def embed_and_search(self, index: str, query: str, rows: int = 10, **params: Any) -> Dict[str, Any]:
236
- """Server-side one-shot: embed the query, run hybrid search, return docs."""
236
+ """Server-side one-shot: embed the query, run the platform's tuned
237
+ hybrid search, return ranked docs.
238
+
239
+ Retrieval uses the same pipeline as the hosted search UI: global
240
+ defaults, overridden by the index's saved Search Tuning (Control
241
+ Panel → Index Settings → Search Tuning), overridden by any of these
242
+ per-call knobs passed as extra params: ``fw_title``,
243
+ ``fw_description``, ``fw_uri``, ``fw_text``, ``fw_text_t``,
244
+ ``lexical_weight``, ``vector_weight``, ``vector_topk``,
245
+ ``search_mode`` (union / keywords_required / meaning_required /
246
+ intersection), ``quality_boost``, ``min_score``,
247
+ ``freshness_boost``, ``lexical_norm_k``, ``mm`` (flexible /
248
+ balanced / strict or raw Solr mm syntax).
249
+ """
237
250
  body = self.ai(
238
251
  "embed_and_search",
239
252
  index_name=index,
@@ -308,8 +321,17 @@ class OpensolrClient:
308
321
  fq: Optional[str] = None,
309
322
  docs: Optional[int] = None,
310
323
  words: Optional[int] = None,
324
+ tuning: Optional[Dict[str, Any]] = None,
311
325
  ) -> str:
312
- """Build the LLM context from the top hybrid search hits."""
326
+ """Build the LLM context from the top hybrid search hits.
327
+
328
+ Retrieval runs through the server-side ``embed_and_search`` pipeline —
329
+ the platform's own tuned hybrid ranking (field weights, minimum-match,
330
+ quality boosts), the same machinery behind the hosted search UI, so it
331
+ improves automatically with the platform. When a custom ``fq`` is
332
+ given (which that endpoint doesn't accept) — or if it fails —
333
+ retrieval falls back to the client-side ``{!hybrid}`` query.
334
+ """
313
335
 
314
336
  def _flat(v: Any) -> str:
315
337
  if isinstance(v, list):
@@ -318,11 +340,21 @@ class OpensolrClient:
318
340
 
319
341
  docs = docs or self.RAG_DOCS
320
342
  words = words or self.RAG_WORDS
321
- body = self.hybrid_search(
322
- index, query, rows=docs, fl="title,description,text", fq=fq
323
- )
343
+ hits: List[Dict[str, Any]] = []
344
+ if not fq:
345
+ try:
346
+ body = self.embed_and_search(index, query, rows=docs, **(tuning or {}))
347
+ if isinstance(body, dict):
348
+ hits = body.get("results", {}).get("docs", []) or []
349
+ except (OpensolrError, httpx.HTTPError):
350
+ hits = []
351
+ if not hits:
352
+ body = self.hybrid_search(
353
+ index, query, rows=docs, fl="title,description,text", fq=fq
354
+ )
355
+ hits = body.get("response", {}).get("docs", [])
324
356
  parts: List[str] = []
325
- for doc in body.get("response", {}).get("docs", []):
357
+ for doc in hits[:docs]:
326
358
  text_words = _flat(doc.get("text")).split()[:words]
327
359
  parts.append(
328
360
  _flat(doc.get("title")) + " - "
@@ -339,6 +371,7 @@ class OpensolrClient:
339
371
  rag_docs: Optional[int] = None,
340
372
  rag_words: Optional[int] = None,
341
373
  instruction: Optional[str] = None,
374
+ tuning: Optional[Dict[str, Any]] = None,
342
375
  **params: Any,
343
376
  ) -> str:
344
377
  """Grounded RAG answer: hybrid retrieval over the index feeds the LLM.
@@ -362,7 +395,8 @@ class OpensolrClient:
362
395
  if "context" not in data:
363
396
  try:
364
397
  context = self._rag_context(
365
- index, query, fq=filter_query, docs=rag_docs, words=rag_words
398
+ index, query, fq=filter_query, docs=rag_docs, words=rag_words,
399
+ tuning=tuning,
366
400
  )
367
401
  except (OpensolrError, httpx.HTTPError):
368
402
  context = ""
@@ -255,6 +255,7 @@ class OpensolrDocumentStore:
255
255
  rag_docs: int = 3,
256
256
  rag_words: int = 1500,
257
257
  instruction: Optional[str] = None,
258
+ tuning: Optional[Dict[str, Any]] = None,
258
259
  **kwargs: Any,
259
260
  ) -> str:
260
261
  """Grounded RAG answer generated only from this index's content.
@@ -264,13 +265,17 @@ class OpensolrDocumentStore:
264
265
  title/description/text become the LLM context — the same pipeline as
265
266
  Opensolr's hosted search UI. Pass ``instruction`` to fully control
266
267
  the prompt (e.g. "Answer in German, cite the sources you used").
267
- Returns plain text.
268
+ Retrieval uses the platform's tuned pipeline: your index's saved
269
+ Search Tuning (Control Panel) applies automatically; ``tuning``
270
+ overrides any knob per call (fw_title, lexical_weight, search_mode,
271
+ mm, vector_topk, quality_boost, ...). Returns plain text.
268
272
  """
269
273
  fqs = _filters_to_fq(filters)
270
274
  fq = " AND ".join(f"({f})" for f in fqs) if fqs else None
271
275
  return self.client.ai_summary(
272
276
  self.index, query, filter_query=fq,
273
277
  rag_docs=rag_docs, rag_words=rag_words, instruction=instruction,
278
+ tuning=tuning,
274
279
  **kwargs,
275
280
  )
276
281
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opensolr-haystack
3
- Version: 0.2.2
3
+ Version: 0.2.4
4
4
  Summary: Haystack integration for Opensolr — managed Apache Solr DocumentStore with server-side embeddings and hybrid BM25+kNN retrieval
5
5
  Author-email: Opensolr <support@opensolr.com>
6
6
  License: MIT
@@ -136,6 +136,23 @@ answer = store.ai_answer(
136
136
  )
137
137
  ```
138
138
 
139
+
140
+ ### Search tuning
141
+
142
+ Retrieval (search and RAG grounding) runs through the platform's tuned
143
+ pipeline: global defaults → your index's saved **Search Tuning** (Control
144
+ Panel → Index Settings → Search Tuning: semantic↔lexical balance, field
145
+ weights, minimum match, search mode, vector candidate pool, content quality
146
+ boost) → optional per-call overrides via `tuning`:
147
+
148
+ ```
149
+ tuning={"search_mode": "keywords_required", "fw_title": 0.2,
150
+ "mm": "strict", "vector_topk": 500, "quality_boost": 0.3}
151
+ ```
152
+
153
+ Defaults match the platform's PHP configuration exactly — customize in the
154
+ Control Panel once, or per call from code.
155
+
139
156
  ## How it's tested
140
157
 
141
158
  Every release is validated against **live Opensolr infrastructure** — no mocks:
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "opensolr-haystack"
7
- version = "0.2.2"
7
+ version = "0.2.4"
8
8
  description = "Haystack integration for Opensolr — managed Apache Solr DocumentStore with server-side embeddings and hybrid BM25+kNN retrieval"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }