elasticsearch9 9.0.0__py3-none-any.whl
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.
- elasticsearch9/__init__.py +98 -0
- elasticsearch9/_async/__init__.py +16 -0
- elasticsearch9/_async/client/__init__.py +6531 -0
- elasticsearch9/_async/client/_base.py +430 -0
- elasticsearch9/_async/client/async_search.py +637 -0
- elasticsearch9/_async/client/autoscaling.py +252 -0
- elasticsearch9/_async/client/cat.py +2995 -0
- elasticsearch9/_async/client/ccr.py +1043 -0
- elasticsearch9/_async/client/cluster.py +1223 -0
- elasticsearch9/_async/client/connector.py +1978 -0
- elasticsearch9/_async/client/dangling_indices.py +192 -0
- elasticsearch9/_async/client/enrich.py +291 -0
- elasticsearch9/_async/client/eql.py +359 -0
- elasticsearch9/_async/client/esql.py +490 -0
- elasticsearch9/_async/client/features.py +130 -0
- elasticsearch9/_async/client/fleet.py +658 -0
- elasticsearch9/_async/client/graph.py +113 -0
- elasticsearch9/_async/client/ilm.py +668 -0
- elasticsearch9/_async/client/indices.py +5582 -0
- elasticsearch9/_async/client/inference.py +2247 -0
- elasticsearch9/_async/client/ingest.py +766 -0
- elasticsearch9/_async/client/license.py +400 -0
- elasticsearch9/_async/client/logstash.py +176 -0
- elasticsearch9/_async/client/migration.py +160 -0
- elasticsearch9/_async/client/ml.py +5835 -0
- elasticsearch9/_async/client/monitoring.py +100 -0
- elasticsearch9/_async/client/nodes.py +543 -0
- elasticsearch9/_async/client/query_rules.py +485 -0
- elasticsearch9/_async/client/rollup.py +616 -0
- elasticsearch9/_async/client/search_application.py +574 -0
- elasticsearch9/_async/client/searchable_snapshots.py +313 -0
- elasticsearch9/_async/client/security.py +4688 -0
- elasticsearch9/_async/client/shutdown.py +268 -0
- elasticsearch9/_async/client/simulate.py +145 -0
- elasticsearch9/_async/client/slm.py +559 -0
- elasticsearch9/_async/client/snapshot.py +1338 -0
- elasticsearch9/_async/client/sql.py +469 -0
- elasticsearch9/_async/client/ssl.py +76 -0
- elasticsearch9/_async/client/synonyms.py +413 -0
- elasticsearch9/_async/client/tasks.py +295 -0
- elasticsearch9/_async/client/text_structure.py +664 -0
- elasticsearch9/_async/client/transform.py +922 -0
- elasticsearch9/_async/client/utils.py +48 -0
- elasticsearch9/_async/client/watcher.py +894 -0
- elasticsearch9/_async/client/xpack.py +134 -0
- elasticsearch9/_async/helpers.py +596 -0
- elasticsearch9/_otel.py +110 -0
- elasticsearch9/_sync/__init__.py +16 -0
- elasticsearch9/_sync/client/__init__.py +6529 -0
- elasticsearch9/_sync/client/_base.py +430 -0
- elasticsearch9/_sync/client/async_search.py +637 -0
- elasticsearch9/_sync/client/autoscaling.py +252 -0
- elasticsearch9/_sync/client/cat.py +2995 -0
- elasticsearch9/_sync/client/ccr.py +1043 -0
- elasticsearch9/_sync/client/cluster.py +1223 -0
- elasticsearch9/_sync/client/connector.py +1978 -0
- elasticsearch9/_sync/client/dangling_indices.py +192 -0
- elasticsearch9/_sync/client/enrich.py +291 -0
- elasticsearch9/_sync/client/eql.py +359 -0
- elasticsearch9/_sync/client/esql.py +490 -0
- elasticsearch9/_sync/client/features.py +130 -0
- elasticsearch9/_sync/client/fleet.py +658 -0
- elasticsearch9/_sync/client/graph.py +113 -0
- elasticsearch9/_sync/client/ilm.py +668 -0
- elasticsearch9/_sync/client/indices.py +5582 -0
- elasticsearch9/_sync/client/inference.py +2247 -0
- elasticsearch9/_sync/client/ingest.py +766 -0
- elasticsearch9/_sync/client/license.py +400 -0
- elasticsearch9/_sync/client/logstash.py +176 -0
- elasticsearch9/_sync/client/migration.py +160 -0
- elasticsearch9/_sync/client/ml.py +5835 -0
- elasticsearch9/_sync/client/monitoring.py +100 -0
- elasticsearch9/_sync/client/nodes.py +543 -0
- elasticsearch9/_sync/client/query_rules.py +485 -0
- elasticsearch9/_sync/client/rollup.py +616 -0
- elasticsearch9/_sync/client/search_application.py +574 -0
- elasticsearch9/_sync/client/searchable_snapshots.py +313 -0
- elasticsearch9/_sync/client/security.py +4688 -0
- elasticsearch9/_sync/client/shutdown.py +268 -0
- elasticsearch9/_sync/client/simulate.py +145 -0
- elasticsearch9/_sync/client/slm.py +559 -0
- elasticsearch9/_sync/client/snapshot.py +1338 -0
- elasticsearch9/_sync/client/sql.py +469 -0
- elasticsearch9/_sync/client/ssl.py +76 -0
- elasticsearch9/_sync/client/synonyms.py +413 -0
- elasticsearch9/_sync/client/tasks.py +295 -0
- elasticsearch9/_sync/client/text_structure.py +664 -0
- elasticsearch9/_sync/client/transform.py +922 -0
- elasticsearch9/_sync/client/utils.py +475 -0
- elasticsearch9/_sync/client/watcher.py +894 -0
- elasticsearch9/_sync/client/xpack.py +134 -0
- elasticsearch9/_utils.py +34 -0
- elasticsearch9/_version.py +18 -0
- elasticsearch9/client.py +126 -0
- elasticsearch9/compat.py +79 -0
- elasticsearch9/dsl/__init__.py +203 -0
- elasticsearch9/dsl/_async/__init__.py +16 -0
- elasticsearch9/dsl/_async/document.py +522 -0
- elasticsearch9/dsl/_async/faceted_search.py +50 -0
- elasticsearch9/dsl/_async/index.py +639 -0
- elasticsearch9/dsl/_async/mapping.py +49 -0
- elasticsearch9/dsl/_async/search.py +237 -0
- elasticsearch9/dsl/_async/update_by_query.py +47 -0
- elasticsearch9/dsl/_sync/__init__.py +16 -0
- elasticsearch9/dsl/_sync/document.py +514 -0
- elasticsearch9/dsl/_sync/faceted_search.py +50 -0
- elasticsearch9/dsl/_sync/index.py +597 -0
- elasticsearch9/dsl/_sync/mapping.py +49 -0
- elasticsearch9/dsl/_sync/search.py +230 -0
- elasticsearch9/dsl/_sync/update_by_query.py +45 -0
- elasticsearch9/dsl/aggs.py +3734 -0
- elasticsearch9/dsl/analysis.py +341 -0
- elasticsearch9/dsl/async_connections.py +37 -0
- elasticsearch9/dsl/connections.py +142 -0
- elasticsearch9/dsl/document.py +20 -0
- elasticsearch9/dsl/document_base.py +444 -0
- elasticsearch9/dsl/exceptions.py +32 -0
- elasticsearch9/dsl/faceted_search.py +28 -0
- elasticsearch9/dsl/faceted_search_base.py +489 -0
- elasticsearch9/dsl/field.py +4392 -0
- elasticsearch9/dsl/function.py +180 -0
- elasticsearch9/dsl/index.py +23 -0
- elasticsearch9/dsl/index_base.py +178 -0
- elasticsearch9/dsl/mapping.py +19 -0
- elasticsearch9/dsl/mapping_base.py +219 -0
- elasticsearch9/dsl/query.py +2822 -0
- elasticsearch9/dsl/response/__init__.py +388 -0
- elasticsearch9/dsl/response/aggs.py +100 -0
- elasticsearch9/dsl/response/hit.py +53 -0
- elasticsearch9/dsl/search.py +20 -0
- elasticsearch9/dsl/search_base.py +1053 -0
- elasticsearch9/dsl/serializer.py +34 -0
- elasticsearch9/dsl/types.py +6453 -0
- elasticsearch9/dsl/update_by_query.py +19 -0
- elasticsearch9/dsl/update_by_query_base.py +149 -0
- elasticsearch9/dsl/utils.py +687 -0
- elasticsearch9/dsl/wrappers.py +144 -0
- elasticsearch9/exceptions.py +133 -0
- elasticsearch9/helpers/__init__.py +41 -0
- elasticsearch9/helpers/actions.py +875 -0
- elasticsearch9/helpers/errors.py +40 -0
- elasticsearch9/helpers/vectorstore/__init__.py +62 -0
- elasticsearch9/helpers/vectorstore/_async/__init__.py +16 -0
- elasticsearch9/helpers/vectorstore/_async/_utils.py +39 -0
- elasticsearch9/helpers/vectorstore/_async/embedding_service.py +89 -0
- elasticsearch9/helpers/vectorstore/_async/strategies.py +487 -0
- elasticsearch9/helpers/vectorstore/_async/vectorstore.py +421 -0
- elasticsearch9/helpers/vectorstore/_sync/__init__.py +16 -0
- elasticsearch9/helpers/vectorstore/_sync/_utils.py +39 -0
- elasticsearch9/helpers/vectorstore/_sync/embedding_service.py +89 -0
- elasticsearch9/helpers/vectorstore/_sync/strategies.py +487 -0
- elasticsearch9/helpers/vectorstore/_sync/vectorstore.py +421 -0
- elasticsearch9/helpers/vectorstore/_utils.py +116 -0
- elasticsearch9/py.typed +0 -0
- elasticsearch9/serializer.py +250 -0
- elasticsearch9-9.0.0.dist-info/METADATA +175 -0
- elasticsearch9-9.0.0.dist-info/RECORD +160 -0
- elasticsearch9-9.0.0.dist-info/WHEEL +4 -0
- elasticsearch9-9.0.0.dist-info/licenses/LICENSE +176 -0
- elasticsearch9-9.0.0.dist-info/licenses/NOTICE +2 -0
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
# Licensed to Elasticsearch B.V. under one or more contributor
|
|
2
|
+
# license agreements. See the NOTICE file distributed with
|
|
3
|
+
# this work for additional information regarding copyright
|
|
4
|
+
# ownership. Elasticsearch B.V. licenses this file to you under
|
|
5
|
+
# the Apache License, Version 2.0 (the "License"); you may
|
|
6
|
+
# not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing,
|
|
12
|
+
# software distributed under the License is distributed on an
|
|
13
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
14
|
+
# KIND, either express or implied. See the License for the
|
|
15
|
+
# specific language governing permissions and limitations
|
|
16
|
+
# under the License.
|
|
17
|
+
|
|
18
|
+
from abc import ABC, abstractmethod
|
|
19
|
+
from typing import Any, Dict, List, Optional, Tuple, Union, cast
|
|
20
|
+
|
|
21
|
+
from elasticsearch import Elasticsearch
|
|
22
|
+
from elasticsearch.helpers.vectorstore._sync._utils import model_must_be_deployed
|
|
23
|
+
from elasticsearch.helpers.vectorstore._utils import DistanceMetric
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class RetrievalStrategy(ABC):
|
|
27
|
+
@abstractmethod
|
|
28
|
+
def es_query(
|
|
29
|
+
self,
|
|
30
|
+
*,
|
|
31
|
+
query: Optional[str],
|
|
32
|
+
query_vector: Optional[List[float]],
|
|
33
|
+
text_field: str,
|
|
34
|
+
vector_field: str,
|
|
35
|
+
k: int,
|
|
36
|
+
num_candidates: int,
|
|
37
|
+
filter: List[Dict[str, Any]] = [],
|
|
38
|
+
) -> Dict[str, Any]:
|
|
39
|
+
"""
|
|
40
|
+
Returns the Elasticsearch query body for the given parameters.
|
|
41
|
+
The store will execute the query.
|
|
42
|
+
|
|
43
|
+
:param query: The text query. Can be None if query_vector is given.
|
|
44
|
+
:param k: The total number of results to retrieve.
|
|
45
|
+
:param num_candidates: The number of results to fetch initially in knn search.
|
|
46
|
+
:param filter: List of filter clauses to apply to the query.
|
|
47
|
+
:param query_vector: The query vector. Can be None if a query string is given.
|
|
48
|
+
|
|
49
|
+
:return: The Elasticsearch query body.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
@abstractmethod
|
|
53
|
+
def es_mappings_settings(
|
|
54
|
+
self,
|
|
55
|
+
*,
|
|
56
|
+
text_field: str,
|
|
57
|
+
vector_field: str,
|
|
58
|
+
num_dimensions: Optional[int],
|
|
59
|
+
) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
60
|
+
"""
|
|
61
|
+
Create the required index and do necessary preliminary work, like
|
|
62
|
+
creating inference pipelines or checking if a required model was deployed.
|
|
63
|
+
|
|
64
|
+
:param client: Elasticsearch client connection.
|
|
65
|
+
:param text_field: The field containing the text data in the index.
|
|
66
|
+
:param vector_field: The field containing the vector representations in the index.
|
|
67
|
+
:param num_dimensions: If vectors are indexed, how many dimensions do they have.
|
|
68
|
+
|
|
69
|
+
:return: Dictionary with field and field type pairs that describe the schema.
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
def before_index_creation(
|
|
73
|
+
self, *, client: Elasticsearch, text_field: str, vector_field: str
|
|
74
|
+
) -> None:
|
|
75
|
+
"""
|
|
76
|
+
Executes before the index is created. Used for setting up
|
|
77
|
+
any required Elasticsearch resources like a pipeline.
|
|
78
|
+
Defaults to a no-op.
|
|
79
|
+
|
|
80
|
+
:param client: The Elasticsearch client.
|
|
81
|
+
:param text_field: The field containing the text data in the index.
|
|
82
|
+
:param vector_field: The field containing the vector representations in the index.
|
|
83
|
+
"""
|
|
84
|
+
pass
|
|
85
|
+
|
|
86
|
+
def needs_inference(self) -> bool:
|
|
87
|
+
"""
|
|
88
|
+
Some retrieval strategies index embedding vectors and allow search by embedding
|
|
89
|
+
vector, for example the `DenseVectorStrategy` strategy. Mapping a user input query
|
|
90
|
+
string to an embedding vector is called inference. Inference can be applied
|
|
91
|
+
in Elasticsearch (using a `model_id`) or outside of Elasticsearch (using an
|
|
92
|
+
`EmbeddingService` defined on the `VectorStore`). In the latter case,
|
|
93
|
+
this method has to return True.
|
|
94
|
+
"""
|
|
95
|
+
return False
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class SparseVectorStrategy(RetrievalStrategy):
|
|
99
|
+
"""Sparse retrieval strategy using the `sparse_vector` processor."""
|
|
100
|
+
|
|
101
|
+
def __init__(self, model_id: str = ".elser_model_2"):
|
|
102
|
+
self.model_id = model_id
|
|
103
|
+
self._tokens_field = "tokens"
|
|
104
|
+
self._pipeline_name = f"{self.model_id}_sparse_embedding"
|
|
105
|
+
|
|
106
|
+
def es_query(
|
|
107
|
+
self,
|
|
108
|
+
*,
|
|
109
|
+
query: Optional[str],
|
|
110
|
+
query_vector: Optional[List[float]],
|
|
111
|
+
text_field: str,
|
|
112
|
+
vector_field: str,
|
|
113
|
+
k: int,
|
|
114
|
+
num_candidates: int,
|
|
115
|
+
filter: List[Dict[str, Any]] = [],
|
|
116
|
+
) -> Dict[str, Any]:
|
|
117
|
+
if query_vector:
|
|
118
|
+
raise ValueError(
|
|
119
|
+
"Cannot do sparse retrieval with a query_vector. "
|
|
120
|
+
"Inference is currently always applied in Elasticsearch."
|
|
121
|
+
)
|
|
122
|
+
if query is None:
|
|
123
|
+
raise ValueError("please specify a query string")
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
"query": {
|
|
127
|
+
"bool": {
|
|
128
|
+
"must": [
|
|
129
|
+
{
|
|
130
|
+
"sparse_vector": {
|
|
131
|
+
"field": f"{vector_field}.{self._tokens_field}",
|
|
132
|
+
"inference_id": self.model_id,
|
|
133
|
+
"query": query,
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
],
|
|
137
|
+
"filter": filter,
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
def es_mappings_settings(
|
|
143
|
+
self,
|
|
144
|
+
*,
|
|
145
|
+
text_field: str,
|
|
146
|
+
vector_field: str,
|
|
147
|
+
num_dimensions: Optional[int],
|
|
148
|
+
) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
149
|
+
mappings: Dict[str, Any] = {
|
|
150
|
+
"properties": {
|
|
151
|
+
vector_field: {
|
|
152
|
+
"properties": {self._tokens_field: {"type": "sparse_vector"}}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
settings = {"default_pipeline": self._pipeline_name}
|
|
157
|
+
|
|
158
|
+
return mappings, settings
|
|
159
|
+
|
|
160
|
+
def before_index_creation(
|
|
161
|
+
self, *, client: Elasticsearch, text_field: str, vector_field: str
|
|
162
|
+
) -> None:
|
|
163
|
+
if self.model_id:
|
|
164
|
+
model_must_be_deployed(client, self.model_id)
|
|
165
|
+
|
|
166
|
+
# Create a pipeline for the model
|
|
167
|
+
client.ingest.put_pipeline(
|
|
168
|
+
id=self._pipeline_name,
|
|
169
|
+
description="Embedding pipeline for Python VectorStore",
|
|
170
|
+
processors=[
|
|
171
|
+
{
|
|
172
|
+
"inference": {
|
|
173
|
+
"model_id": self.model_id,
|
|
174
|
+
"input_output": [
|
|
175
|
+
{
|
|
176
|
+
"input_field": text_field,
|
|
177
|
+
"output_field": f"{vector_field}.{self._tokens_field}",
|
|
178
|
+
},
|
|
179
|
+
],
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
],
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class DenseVectorStrategy(RetrievalStrategy):
|
|
187
|
+
"""K-nearest-neighbors retrieval."""
|
|
188
|
+
|
|
189
|
+
def __init__(
|
|
190
|
+
self,
|
|
191
|
+
*,
|
|
192
|
+
distance: DistanceMetric = DistanceMetric.COSINE,
|
|
193
|
+
model_id: Optional[str] = None,
|
|
194
|
+
hybrid: bool = False,
|
|
195
|
+
rrf: Union[bool, Dict[str, Any]] = True,
|
|
196
|
+
text_field: Optional[str] = "text_field",
|
|
197
|
+
):
|
|
198
|
+
if hybrid and not text_field:
|
|
199
|
+
raise ValueError(
|
|
200
|
+
"to enable hybrid you have to specify a text_field (for BM25Strategy matching)"
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
self.distance = distance
|
|
204
|
+
self.model_id = model_id
|
|
205
|
+
self.hybrid = hybrid
|
|
206
|
+
self.rrf = rrf
|
|
207
|
+
self.text_field = text_field
|
|
208
|
+
|
|
209
|
+
def es_query(
|
|
210
|
+
self,
|
|
211
|
+
*,
|
|
212
|
+
query: Optional[str],
|
|
213
|
+
query_vector: Optional[List[float]],
|
|
214
|
+
text_field: str,
|
|
215
|
+
vector_field: str,
|
|
216
|
+
k: int,
|
|
217
|
+
num_candidates: int,
|
|
218
|
+
filter: List[Dict[str, Any]] = [],
|
|
219
|
+
) -> Dict[str, Any]:
|
|
220
|
+
knn = {
|
|
221
|
+
"filter": filter,
|
|
222
|
+
"field": vector_field,
|
|
223
|
+
"k": k,
|
|
224
|
+
"num_candidates": num_candidates,
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if query_vector is not None:
|
|
228
|
+
knn["query_vector"] = query_vector
|
|
229
|
+
else:
|
|
230
|
+
# Inference in Elasticsearch. When initializing we make sure to always have
|
|
231
|
+
# a model_id if don't have an embedding_service.
|
|
232
|
+
knn["query_vector_builder"] = {
|
|
233
|
+
"text_embedding": {
|
|
234
|
+
"model_id": self.model_id,
|
|
235
|
+
"model_text": query,
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if self.hybrid:
|
|
240
|
+
return self._hybrid(query=cast(str, query), knn=knn, filter=filter)
|
|
241
|
+
|
|
242
|
+
return {"knn": knn}
|
|
243
|
+
|
|
244
|
+
def es_mappings_settings(
|
|
245
|
+
self,
|
|
246
|
+
*,
|
|
247
|
+
text_field: str,
|
|
248
|
+
vector_field: str,
|
|
249
|
+
num_dimensions: Optional[int],
|
|
250
|
+
) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
251
|
+
if self.distance is DistanceMetric.COSINE:
|
|
252
|
+
similarity = "cosine"
|
|
253
|
+
elif self.distance is DistanceMetric.EUCLIDEAN_DISTANCE:
|
|
254
|
+
similarity = "l2_norm"
|
|
255
|
+
elif self.distance is DistanceMetric.DOT_PRODUCT:
|
|
256
|
+
similarity = "dot_product"
|
|
257
|
+
elif self.distance is DistanceMetric.MAX_INNER_PRODUCT:
|
|
258
|
+
similarity = "max_inner_product"
|
|
259
|
+
else:
|
|
260
|
+
raise ValueError(f"Similarity {self.distance} not supported.")
|
|
261
|
+
|
|
262
|
+
mappings: Dict[str, Any] = {
|
|
263
|
+
"properties": {
|
|
264
|
+
vector_field: {
|
|
265
|
+
"type": "dense_vector",
|
|
266
|
+
"dims": num_dimensions,
|
|
267
|
+
"index": True,
|
|
268
|
+
"similarity": similarity,
|
|
269
|
+
},
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return mappings, {}
|
|
274
|
+
|
|
275
|
+
def before_index_creation(
|
|
276
|
+
self, *, client: Elasticsearch, text_field: str, vector_field: str
|
|
277
|
+
) -> None:
|
|
278
|
+
if self.model_id:
|
|
279
|
+
model_must_be_deployed(client, self.model_id)
|
|
280
|
+
|
|
281
|
+
def _hybrid(
|
|
282
|
+
self, query: str, knn: Dict[str, Any], filter: List[Dict[str, Any]]
|
|
283
|
+
) -> Dict[str, Any]:
|
|
284
|
+
# Add a query to the knn query.
|
|
285
|
+
# RRF is used to even the score from the knn query and text query
|
|
286
|
+
# RRF has two optional parameters: {'rank_constant':int, 'rank_window_size':int}
|
|
287
|
+
# https://www.elastic.co/guide/en/elasticsearch/reference/current/rrf.html
|
|
288
|
+
standard_query = {
|
|
289
|
+
"query": {
|
|
290
|
+
"bool": {
|
|
291
|
+
"must": [
|
|
292
|
+
{
|
|
293
|
+
"match": {
|
|
294
|
+
self.text_field: {
|
|
295
|
+
"query": query,
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
],
|
|
300
|
+
"filter": filter,
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if self.rrf is False:
|
|
306
|
+
query_body = {
|
|
307
|
+
"knn": knn,
|
|
308
|
+
**standard_query,
|
|
309
|
+
}
|
|
310
|
+
else:
|
|
311
|
+
rrf_options = {}
|
|
312
|
+
if isinstance(self.rrf, Dict):
|
|
313
|
+
if "rank_constant" in self.rrf:
|
|
314
|
+
rrf_options["rank_constant"] = self.rrf["rank_constant"]
|
|
315
|
+
if "window_size" in self.rrf:
|
|
316
|
+
# 'window_size' was renamed to 'rank_window_size', but we support
|
|
317
|
+
# the older name for backwards compatibility
|
|
318
|
+
rrf_options["rank_window_size"] = self.rrf["window_size"]
|
|
319
|
+
if "rank_window_size" in self.rrf:
|
|
320
|
+
rrf_options["rank_window_size"] = self.rrf["rank_window_size"]
|
|
321
|
+
query_body = {
|
|
322
|
+
"retriever": {
|
|
323
|
+
"rrf": {
|
|
324
|
+
"retrievers": [
|
|
325
|
+
{"standard": standard_query},
|
|
326
|
+
{"knn": knn},
|
|
327
|
+
],
|
|
328
|
+
**rrf_options,
|
|
329
|
+
},
|
|
330
|
+
},
|
|
331
|
+
}
|
|
332
|
+
return query_body
|
|
333
|
+
|
|
334
|
+
def needs_inference(self) -> bool:
|
|
335
|
+
return not self.model_id
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
class DenseVectorScriptScoreStrategy(RetrievalStrategy):
|
|
339
|
+
"""Exact nearest neighbors retrieval using the `script_score` query."""
|
|
340
|
+
|
|
341
|
+
def __init__(self, distance: DistanceMetric = DistanceMetric.COSINE) -> None:
|
|
342
|
+
self.distance = distance
|
|
343
|
+
|
|
344
|
+
def es_query(
|
|
345
|
+
self,
|
|
346
|
+
*,
|
|
347
|
+
query: Optional[str],
|
|
348
|
+
query_vector: Optional[List[float]],
|
|
349
|
+
text_field: str,
|
|
350
|
+
vector_field: str,
|
|
351
|
+
k: int,
|
|
352
|
+
num_candidates: int,
|
|
353
|
+
filter: List[Dict[str, Any]] = [],
|
|
354
|
+
) -> Dict[str, Any]:
|
|
355
|
+
if not query_vector:
|
|
356
|
+
raise ValueError("specify a query_vector")
|
|
357
|
+
|
|
358
|
+
if self.distance is DistanceMetric.COSINE:
|
|
359
|
+
similarity_algo = (
|
|
360
|
+
f"cosineSimilarity(params.query_vector, '{vector_field}') + 1.0"
|
|
361
|
+
)
|
|
362
|
+
elif self.distance is DistanceMetric.EUCLIDEAN_DISTANCE:
|
|
363
|
+
similarity_algo = f"1 / (1 + l2norm(params.query_vector, '{vector_field}'))"
|
|
364
|
+
elif self.distance is DistanceMetric.DOT_PRODUCT:
|
|
365
|
+
similarity_algo = f"""
|
|
366
|
+
double value = dotProduct(params.query_vector, '{vector_field}');
|
|
367
|
+
return sigmoid(1, Math.E, -value);
|
|
368
|
+
"""
|
|
369
|
+
elif self.distance is DistanceMetric.MAX_INNER_PRODUCT:
|
|
370
|
+
similarity_algo = f"""
|
|
371
|
+
double value = dotProduct(params.query_vector, '{vector_field}');
|
|
372
|
+
if (dotProduct < 0) {{
|
|
373
|
+
return 1 / (1 + -1 * dotProduct);
|
|
374
|
+
}}
|
|
375
|
+
return dotProduct + 1;
|
|
376
|
+
"""
|
|
377
|
+
else:
|
|
378
|
+
raise ValueError(f"Similarity {self.distance} not supported.")
|
|
379
|
+
|
|
380
|
+
query_bool: Dict[str, Any] = {"match_all": {}}
|
|
381
|
+
if filter:
|
|
382
|
+
query_bool = {"bool": {"filter": filter}}
|
|
383
|
+
|
|
384
|
+
return {
|
|
385
|
+
"query": {
|
|
386
|
+
"script_score": {
|
|
387
|
+
"query": query_bool,
|
|
388
|
+
"script": {
|
|
389
|
+
"source": similarity_algo,
|
|
390
|
+
"params": {"query_vector": query_vector},
|
|
391
|
+
},
|
|
392
|
+
},
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
def es_mappings_settings(
|
|
397
|
+
self,
|
|
398
|
+
*,
|
|
399
|
+
text_field: str,
|
|
400
|
+
vector_field: str,
|
|
401
|
+
num_dimensions: Optional[int],
|
|
402
|
+
) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
403
|
+
mappings = {
|
|
404
|
+
"properties": {
|
|
405
|
+
vector_field: {
|
|
406
|
+
"type": "dense_vector",
|
|
407
|
+
"dims": num_dimensions,
|
|
408
|
+
"index": False,
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
return mappings, {}
|
|
414
|
+
|
|
415
|
+
def needs_inference(self) -> bool:
|
|
416
|
+
return True
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
class BM25Strategy(RetrievalStrategy):
|
|
420
|
+
def __init__(
|
|
421
|
+
self,
|
|
422
|
+
k1: Optional[float] = None,
|
|
423
|
+
b: Optional[float] = None,
|
|
424
|
+
):
|
|
425
|
+
self.k1 = k1
|
|
426
|
+
self.b = b
|
|
427
|
+
|
|
428
|
+
def es_query(
|
|
429
|
+
self,
|
|
430
|
+
*,
|
|
431
|
+
query: Optional[str],
|
|
432
|
+
query_vector: Optional[List[float]],
|
|
433
|
+
text_field: str,
|
|
434
|
+
vector_field: str,
|
|
435
|
+
k: int,
|
|
436
|
+
num_candidates: int,
|
|
437
|
+
filter: List[Dict[str, Any]] = [],
|
|
438
|
+
) -> Dict[str, Any]:
|
|
439
|
+
return {
|
|
440
|
+
"query": {
|
|
441
|
+
"bool": {
|
|
442
|
+
"must": [
|
|
443
|
+
{
|
|
444
|
+
"match": {
|
|
445
|
+
text_field: {
|
|
446
|
+
"query": query,
|
|
447
|
+
}
|
|
448
|
+
},
|
|
449
|
+
},
|
|
450
|
+
],
|
|
451
|
+
"filter": filter,
|
|
452
|
+
},
|
|
453
|
+
},
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
def es_mappings_settings(
|
|
457
|
+
self,
|
|
458
|
+
*,
|
|
459
|
+
text_field: str,
|
|
460
|
+
vector_field: str,
|
|
461
|
+
num_dimensions: Optional[int],
|
|
462
|
+
) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
463
|
+
similarity_name = "custom_bm25"
|
|
464
|
+
|
|
465
|
+
mappings: Dict[str, Any] = {
|
|
466
|
+
"properties": {
|
|
467
|
+
text_field: {
|
|
468
|
+
"type": "text",
|
|
469
|
+
"similarity": similarity_name,
|
|
470
|
+
},
|
|
471
|
+
},
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
bm25: Dict[str, Any] = {
|
|
475
|
+
"type": "BM25",
|
|
476
|
+
}
|
|
477
|
+
if self.k1 is not None:
|
|
478
|
+
bm25["k1"] = self.k1
|
|
479
|
+
if self.b is not None:
|
|
480
|
+
bm25["b"] = self.b
|
|
481
|
+
settings = {
|
|
482
|
+
"similarity": {
|
|
483
|
+
similarity_name: bm25,
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
return mappings, settings
|