nucliadb 6.3.4.post3817__py3-none-any.whl → 6.3.4.post3823__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.
- nucliadb/ingest/orm/entities.py +14 -17
- nucliadb/search/search/graph_strategy.py +25 -16
- nucliadb/search/search/merge.py +0 -13
- nucliadb/search/search/query_parser/fetcher.py +104 -133
- nucliadb/search/search/query_parser/parsers/graph.py +5 -4
- {nucliadb-6.3.4.post3817.dist-info → nucliadb-6.3.4.post3823.dist-info}/METADATA +6 -6
- {nucliadb-6.3.4.post3817.dist-info → nucliadb-6.3.4.post3823.dist-info}/RECORD +10 -10
- {nucliadb-6.3.4.post3817.dist-info → nucliadb-6.3.4.post3823.dist-info}/WHEEL +0 -0
- {nucliadb-6.3.4.post3817.dist-info → nucliadb-6.3.4.post3823.dist-info}/entry_points.txt +0 -0
- {nucliadb-6.3.4.post3817.dist-info → nucliadb-6.3.4.post3823.dist-info}/top_level.txt +0 -0
nucliadb/ingest/orm/entities.py
CHANGED
@@ -36,7 +36,7 @@ from nucliadb.common.datamanagers.entities import (
|
|
36
36
|
from nucliadb.common.maindb.driver import Transaction
|
37
37
|
from nucliadb.ingest.orm.knowledgebox import KnowledgeBox
|
38
38
|
from nucliadb.ingest.settings import settings
|
39
|
-
from nucliadb.search.search.shards import query_shard
|
39
|
+
from nucliadb.search.search.shards import graph_search_shard, query_shard
|
40
40
|
from nucliadb_protos.knowledgebox_pb2 import (
|
41
41
|
DeletedEntitiesGroups,
|
42
42
|
EntitiesGroup,
|
@@ -45,9 +45,8 @@ from nucliadb_protos.knowledgebox_pb2 import (
|
|
45
45
|
)
|
46
46
|
from nucliadb_protos.nodereader_pb2 import (
|
47
47
|
Faceted,
|
48
|
-
|
49
|
-
|
50
|
-
RelationSearchResponse,
|
48
|
+
GraphSearchRequest,
|
49
|
+
GraphSearchResponse,
|
51
50
|
SearchRequest,
|
52
51
|
SearchResponse,
|
53
52
|
)
|
@@ -203,18 +202,16 @@ class EntitiesManager:
|
|
203
202
|
async def get_indexed_entities_group(self, group: str) -> Optional[EntitiesGroup]:
|
204
203
|
shard_manager = get_shard_manager()
|
205
204
|
|
206
|
-
async def do_entities_search(node: AbstractIndexNode, shard_id: str) ->
|
207
|
-
request =
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
response = await query_shard(node, shard_id, request)
|
217
|
-
return response.relation
|
205
|
+
async def do_entities_search(node: AbstractIndexNode, shard_id: str) -> GraphSearchResponse:
|
206
|
+
request = GraphSearchRequest()
|
207
|
+
# XXX: this is a wild guess. Are those enough or too many?
|
208
|
+
request.top_k = 500
|
209
|
+
request.kind = GraphSearchRequest.QueryKind.NODES
|
210
|
+
request.query.path.path.source.node_type = RelationNode.NodeType.ENTITY
|
211
|
+
request.query.path.path.source.node_subtype = group
|
212
|
+
request.query.path.path.undirected = True
|
213
|
+
response = await graph_search_shard(node, shard_id, request)
|
214
|
+
return response
|
218
215
|
|
219
216
|
results = await shard_manager.apply_for_all_shards(
|
220
217
|
self.kbid,
|
@@ -224,7 +221,7 @@ class EntitiesManager:
|
|
224
221
|
|
225
222
|
entities = {}
|
226
223
|
for result in results:
|
227
|
-
entities.update({node.value: Entity(value=node.value) for node in result.
|
224
|
+
entities.update({node.value: Entity(value=node.value) for node in result.nodes})
|
228
225
|
|
229
226
|
if not entities:
|
230
227
|
return None
|
@@ -44,7 +44,6 @@ from nucliadb.search.search.find_merge import (
|
|
44
44
|
hydrate_and_rerank,
|
45
45
|
)
|
46
46
|
from nucliadb.search.search.hydrator import ResourceHydrationOptions, TextBlockHydrationOptions
|
47
|
-
from nucliadb.search.search.merge import merge_relation_prefix_results
|
48
47
|
from nucliadb.search.search.metrics import RAGMetrics
|
49
48
|
from nucliadb.search.search.rerankers import Reranker, RerankingOptions
|
50
49
|
from nucliadb.search.utilities import get_predict
|
@@ -65,6 +64,7 @@ from nucliadb_models.search import (
|
|
65
64
|
NucliaDBClientType,
|
66
65
|
QueryEntityDetection,
|
67
66
|
RelatedEntities,
|
67
|
+
RelatedEntity,
|
68
68
|
RelationDirection,
|
69
69
|
RelationRanking,
|
70
70
|
Relations,
|
@@ -443,26 +443,35 @@ async def fuzzy_search_entities(
|
|
443
443
|
) -> Optional[RelatedEntities]:
|
444
444
|
"""Fuzzy find entities in KB given a query using the same methodology as /suggest, but split by words."""
|
445
445
|
|
446
|
-
|
447
|
-
|
446
|
+
# Build an OR for each word in the query matching with fuzzy any word in any
|
447
|
+
# node in any position. I.e., for the query "Rose Hamiltn", it'll match
|
448
|
+
# "Rosa Parks" and "Margaret Hamilton"
|
449
|
+
request = nodereader_pb2.GraphSearchRequest()
|
450
|
+
# XXX Are those enough results? Too many?
|
451
|
+
request.top_k = 50
|
452
|
+
request.kind = nodereader_pb2.GraphSearchRequest.QueryKind.NODES
|
453
|
+
for word in query.split():
|
454
|
+
subquery = nodereader_pb2.GraphQuery.PathQuery()
|
455
|
+
subquery.path.source.value = word
|
456
|
+
subquery.path.source.fuzzy.kind = nodereader_pb2.GraphQuery.Node.MatchLocation.WORDS
|
457
|
+
subquery.path.source.fuzzy.distance = 1
|
458
|
+
subquery.path.undirected = True
|
459
|
+
request.query.path.bool_or.operands.append(subquery)
|
448
460
|
|
449
|
-
results: list[nodereader_pb2.SearchResponse]
|
450
461
|
try:
|
451
|
-
(
|
452
|
-
|
453
|
-
|
454
|
-
_,
|
455
|
-
) = await node_query(
|
456
|
-
kbid,
|
457
|
-
Method.SEARCH,
|
458
|
-
request,
|
459
|
-
)
|
460
|
-
return merge_relation_prefix_results(results)
|
461
|
-
except Exception as e:
|
462
|
-
capture_exception(e)
|
462
|
+
results, _, _ = await node_query(kbid, Method.GRAPH, request)
|
463
|
+
except Exception as exc:
|
464
|
+
capture_exception(exc)
|
463
465
|
logger.exception("Error in finding entities in query for graph strategy")
|
464
466
|
return None
|
465
467
|
|
468
|
+
# merge shard results while deduplicating repeated entities across shards
|
469
|
+
unique_entities: set[RelatedEntity] = set()
|
470
|
+
for response in results:
|
471
|
+
unique_entities.update((RelatedEntity(family=e.subtype, value=e.value) for e in response.nodes))
|
472
|
+
|
473
|
+
return RelatedEntities(entities=list(unique_entities), total=len(unique_entities))
|
474
|
+
|
466
475
|
|
467
476
|
async def rank_relations_reranker(
|
468
477
|
relations: Relations,
|
nucliadb/search/search/merge.py
CHANGED
@@ -632,19 +632,6 @@ async def merge_suggest_entities_results(
|
|
632
632
|
return RelatedEntities(entities=list(unique_entities), total=len(unique_entities))
|
633
633
|
|
634
634
|
|
635
|
-
def merge_relation_prefix_results(
|
636
|
-
responses: list[SearchResponse],
|
637
|
-
) -> RelatedEntities:
|
638
|
-
unique_entities: Set[RelatedEntity] = set()
|
639
|
-
for response in responses:
|
640
|
-
response_entities = (
|
641
|
-
RelatedEntity(family=e.subtype, value=e.value) for e in response.relation.prefix.nodes
|
642
|
-
)
|
643
|
-
unique_entities.update(response_entities)
|
644
|
-
|
645
|
-
return RelatedEntities(entities=list(unique_entities), total=len(unique_entities))
|
646
|
-
|
647
|
-
|
648
635
|
async def merge_suggest_results(
|
649
636
|
suggest_responses: list[SuggestResponse],
|
650
637
|
kbid: str,
|
@@ -17,6 +17,7 @@
|
|
17
17
|
# You should have received a copy of the GNU Affero General Public License
|
18
18
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
19
|
#
|
20
|
+
import asyncio
|
20
21
|
from typing import Optional, TypeVar, Union
|
21
22
|
|
22
23
|
from async_lru import alru_cache
|
@@ -53,12 +54,9 @@ def is_cached(field: Union[T, NotCached]) -> TypeIs[T]:
|
|
53
54
|
|
54
55
|
class FetcherCache:
|
55
56
|
predict_query_info: Union[Optional[QueryInfo], NotCached] = not_cached
|
56
|
-
predict_detected_entities: Union[list[utils_pb2.RelationNode], NotCached] = not_cached
|
57
57
|
|
58
58
|
# semantic search
|
59
|
-
query_vector: Union[Optional[list[float]], NotCached] = not_cached
|
60
59
|
vectorset: Union[str, NotCached] = not_cached
|
61
|
-
matryoshka_dimension: Union[Optional[int], NotCached] = not_cached
|
62
60
|
|
63
61
|
labels: Union[knowledgebox_pb2.Labels, NotCached] = not_cached
|
64
62
|
|
@@ -97,103 +95,80 @@ class Fetcher:
|
|
97
95
|
self.query = query
|
98
96
|
self.user_vector = user_vector
|
99
97
|
self.user_vectorset = vectorset
|
98
|
+
self.user_vectorset_validated = False
|
100
99
|
self.rephrase = rephrase
|
101
100
|
self.rephrase_prompt = rephrase_prompt
|
102
101
|
self.generative_model = generative_model
|
103
102
|
|
104
103
|
self.cache = FetcherCache()
|
105
|
-
self.
|
106
|
-
|
107
|
-
# Validation
|
108
|
-
|
109
|
-
async def initial_validate(self):
|
110
|
-
"""Runs a validation on the input parameters. It can raise errors if
|
111
|
-
there's some wrong parameter.
|
112
|
-
|
113
|
-
This function should be always called if validated input for fetching is
|
114
|
-
desired
|
115
|
-
"""
|
116
|
-
if self._validated:
|
117
|
-
return
|
118
|
-
|
119
|
-
self._validated = True
|
120
|
-
|
121
|
-
async def _validate_vectorset(self):
|
122
|
-
if self.user_vectorset is not None:
|
123
|
-
await validate_vectorset(self.kbid, self.user_vectorset)
|
104
|
+
self.locks: dict[str, asyncio.Lock] = {}
|
124
105
|
|
125
106
|
# Semantic search
|
126
107
|
|
127
108
|
async def get_matryoshka_dimension(self) -> Optional[int]:
|
128
|
-
if is_cached(self.cache.matryoshka_dimension):
|
129
|
-
return self.cache.matryoshka_dimension
|
130
|
-
|
131
109
|
vectorset = await self.get_vectorset()
|
132
|
-
|
133
|
-
self.cache.matryoshka_dimension = matryoshka_dimension
|
134
|
-
return matryoshka_dimension
|
110
|
+
return await get_matryoshka_dimension_cached(self.kbid, vectorset)
|
135
111
|
|
136
112
|
async def _get_user_vectorset(self) -> Optional[str]:
|
137
113
|
"""Returns the user's requested vectorset and validates if it does exist
|
138
114
|
in the KB.
|
139
115
|
|
140
116
|
"""
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
117
|
+
async with self.locks.setdefault("user_vectorset", asyncio.Lock()):
|
118
|
+
if not self.user_vectorset_validated:
|
119
|
+
if self.user_vectorset is not None:
|
120
|
+
await validate_vectorset(self.kbid, self.user_vectorset)
|
121
|
+
self.user_vectorset_validated = True
|
122
|
+
return self.user_vectorset
|
145
123
|
|
146
124
|
async def get_vectorset(self) -> str:
|
147
125
|
"""Get the vectorset to be used in the search. If not specified, by the
|
148
126
|
user, Predict API or the own uses KB will provide a default.
|
149
127
|
|
150
128
|
"""
|
129
|
+
async with self.locks.setdefault("vectorset", asyncio.Lock()):
|
130
|
+
if is_cached(self.cache.vectorset):
|
131
|
+
return self.cache.vectorset
|
151
132
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
self.cache.vectorset = self.user_vectorset
|
158
|
-
return self.user_vectorset
|
133
|
+
user_vectorset = await self._get_user_vectorset()
|
134
|
+
if user_vectorset:
|
135
|
+
# user explicitly asked for a vectorset
|
136
|
+
self.cache.vectorset = user_vectorset
|
137
|
+
return user_vectorset
|
159
138
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
vectorset = None
|
164
|
-
else:
|
165
|
-
if query_info.sentence is None:
|
166
|
-
logger.error(
|
167
|
-
"Asking for a vectorset but /query didn't return one", extra={"kbid": self.kbid}
|
168
|
-
)
|
139
|
+
# when it's not provided, we get the default from Predict API
|
140
|
+
query_info = await self._predict_query_endpoint()
|
141
|
+
if query_info is None:
|
169
142
|
vectorset = None
|
170
143
|
else:
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
144
|
+
if query_info.sentence is None:
|
145
|
+
logger.error(
|
146
|
+
"Asking for a vectorset but /query didn't return one", extra={"kbid": self.kbid}
|
147
|
+
)
|
148
|
+
vectorset = None
|
149
|
+
else:
|
150
|
+
# vectors field is enforced by the data model to have at least one key
|
151
|
+
for vectorset in query_info.sentence.vectors.keys():
|
152
|
+
vectorset = vectorset
|
153
|
+
break
|
154
|
+
|
155
|
+
if vectorset is None:
|
156
|
+
# in case predict don't answer which vectorset to use, fallback to
|
157
|
+
# the first vectorset of the KB
|
158
|
+
async with datamanagers.with_ro_transaction() as txn:
|
159
|
+
async for vectorset, _ in datamanagers.vectorsets.iter(txn, kbid=self.kbid):
|
160
|
+
break
|
161
|
+
assert vectorset is not None, "All KBs must have at least one vectorset in maindb"
|
162
|
+
|
163
|
+
self.cache.vectorset = vectorset
|
164
|
+
return vectorset
|
186
165
|
|
187
166
|
async def get_query_vector(self) -> Optional[list[float]]:
|
188
|
-
if is_cached(self.cache.query_vector):
|
189
|
-
return self.cache.query_vector
|
190
|
-
|
191
167
|
if self.user_vector is not None:
|
192
168
|
query_vector = self.user_vector
|
193
169
|
else:
|
194
170
|
query_info = await self._predict_query_endpoint()
|
195
171
|
if query_info is None or query_info.sentence is None:
|
196
|
-
self.cache.query_vector = None
|
197
172
|
return None
|
198
173
|
|
199
174
|
vectorset = await self.get_vectorset()
|
@@ -206,7 +181,6 @@ class Fetcher:
|
|
206
181
|
"predict_vectorsets": ",".join(query_info.sentence.vectors.keys()),
|
207
182
|
},
|
208
183
|
)
|
209
|
-
self.cache.query_vector = None
|
210
184
|
return None
|
211
185
|
|
212
186
|
query_vector = query_info.sentence.vectors[vectorset]
|
@@ -223,7 +197,6 @@ class Fetcher:
|
|
223
197
|
# accordingly
|
224
198
|
query_vector = query_vector[:matryoshka_dimension]
|
225
199
|
|
226
|
-
self.cache.query_vector = query_vector
|
227
200
|
return query_vector
|
228
201
|
|
229
202
|
async def get_rephrased_query(self) -> Optional[str]:
|
@@ -235,100 +208,98 @@ class Fetcher:
|
|
235
208
|
# Labels
|
236
209
|
|
237
210
|
async def get_classification_labels(self) -> knowledgebox_pb2.Labels:
|
238
|
-
|
239
|
-
|
211
|
+
async with self.locks.setdefault("classification_labels", asyncio.Lock()):
|
212
|
+
if is_cached(self.cache.labels):
|
213
|
+
return self.cache.labels
|
240
214
|
|
241
|
-
|
242
|
-
|
243
|
-
|
215
|
+
labels = await get_classification_labels(self.kbid)
|
216
|
+
self.cache.labels = labels
|
217
|
+
return labels
|
244
218
|
|
245
219
|
# Entities
|
246
220
|
|
247
221
|
async def get_entities_meta_cache(self) -> datamanagers.entities.EntitiesMetaCache:
|
248
|
-
|
249
|
-
|
222
|
+
async with self.locks.setdefault("entities_meta_cache", asyncio.Lock()):
|
223
|
+
if is_cached(self.cache.entities_meta_cache):
|
224
|
+
return self.cache.entities_meta_cache
|
250
225
|
|
251
|
-
|
252
|
-
|
253
|
-
|
226
|
+
entities_meta_cache = await get_entities_meta_cache(self.kbid)
|
227
|
+
self.cache.entities_meta_cache = entities_meta_cache
|
228
|
+
return entities_meta_cache
|
254
229
|
|
255
230
|
async def get_deleted_entity_groups(self) -> list[str]:
|
256
|
-
|
257
|
-
|
231
|
+
async with self.locks.setdefault("deleted_entity_groups", asyncio.Lock()):
|
232
|
+
if is_cached(self.cache.deleted_entity_groups):
|
233
|
+
return self.cache.deleted_entity_groups
|
258
234
|
|
259
|
-
|
260
|
-
|
261
|
-
|
235
|
+
deleted_entity_groups = await get_deleted_entity_groups(self.kbid)
|
236
|
+
self.cache.deleted_entity_groups = deleted_entity_groups
|
237
|
+
return deleted_entity_groups
|
262
238
|
|
263
239
|
async def get_detected_entities(self) -> list[utils_pb2.RelationNode]:
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
240
|
+
async with self.locks.setdefault("detected_entities", asyncio.Lock()):
|
241
|
+
if is_cached(self.cache.detected_entities):
|
242
|
+
return self.cache.detected_entities
|
243
|
+
|
244
|
+
# Optimization to avoid calling predict twice
|
245
|
+
if is_cached(self.cache.predict_query_info):
|
246
|
+
# /query supersets detect entities, so we already have them
|
247
|
+
query_info = self.cache.predict_query_info
|
248
|
+
if query_info is not None and query_info.entities is not None:
|
249
|
+
detected_entities = convert_relations(query_info.entities.model_dump())
|
250
|
+
else:
|
251
|
+
detected_entities = []
|
273
252
|
else:
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
# endpoint instead (as it's faster)
|
278
|
-
detected_entities = await self._predict_detect_entities()
|
253
|
+
# No call to /query has been done, we'll use detect entities
|
254
|
+
# endpoint instead (as it's faster)
|
255
|
+
detected_entities = await self._predict_detect_entities()
|
279
256
|
|
280
|
-
|
281
|
-
|
257
|
+
self.cache.detected_entities = detected_entities
|
258
|
+
return detected_entities
|
282
259
|
|
283
260
|
# Synonyms
|
284
261
|
|
285
262
|
async def get_synonyms(self) -> Optional[knowledgebox_pb2.Synonyms]:
|
286
|
-
|
287
|
-
|
263
|
+
async with self.locks.setdefault("synonyms", asyncio.Lock()):
|
264
|
+
if is_cached(self.cache.synonyms):
|
265
|
+
return self.cache.synonyms
|
288
266
|
|
289
|
-
|
290
|
-
|
291
|
-
|
267
|
+
synonyms = await get_kb_synonyms(self.kbid)
|
268
|
+
self.cache.synonyms = synonyms
|
269
|
+
return synonyms
|
292
270
|
|
293
271
|
# Predict API
|
294
272
|
|
295
273
|
async def _predict_query_endpoint(self) -> Optional[QueryInfo]:
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
)
|
315
|
-
except (SendToPredictError, TimeoutError):
|
316
|
-
query_info = None
|
274
|
+
async with self.locks.setdefault("predict_query_endpoint", asyncio.Lock()):
|
275
|
+
if is_cached(self.cache.predict_query_info):
|
276
|
+
return self.cache.predict_query_info
|
277
|
+
|
278
|
+
# we can't call get_vectorset, as it would do a recirsive loop between
|
279
|
+
# functions, so we'll manually parse it
|
280
|
+
vectorset = await self._get_user_vectorset()
|
281
|
+
try:
|
282
|
+
query_info = await query_information(
|
283
|
+
self.kbid,
|
284
|
+
self.query,
|
285
|
+
vectorset,
|
286
|
+
self.generative_model,
|
287
|
+
self.rephrase,
|
288
|
+
self.rephrase_prompt,
|
289
|
+
)
|
290
|
+
except (SendToPredictError, TimeoutError):
|
291
|
+
query_info = None
|
317
292
|
|
318
|
-
|
319
|
-
|
293
|
+
self.cache.predict_query_info = query_info
|
294
|
+
return query_info
|
320
295
|
|
321
296
|
async def _predict_detect_entities(self) -> list[utils_pb2.RelationNode]:
|
322
|
-
if is_cached(self.cache.predict_detected_entities):
|
323
|
-
return self.cache.predict_detected_entities
|
324
|
-
|
325
297
|
try:
|
326
298
|
detected_entities = await detect_entities(self.kbid, self.query)
|
327
299
|
except (SendToPredictError, TimeoutError) as ex:
|
328
300
|
logger.warning(f"Errors on Predict API detecting entities: {ex}", extra={"kbid": self.kbid})
|
329
301
|
detected_entities = []
|
330
302
|
|
331
|
-
self.cache.predict_detected_entities = detected_entities
|
332
303
|
return detected_entities
|
333
304
|
|
334
305
|
|
@@ -360,7 +331,7 @@ async def detect_entities(kbid: str, query: str) -> list[utils_pb2.RelationNode]
|
|
360
331
|
|
361
332
|
|
362
333
|
@alru_cache(maxsize=None)
|
363
|
-
async def get_matryoshka_dimension_cached(kbid: str, vectorset:
|
334
|
+
async def get_matryoshka_dimension_cached(kbid: str, vectorset: str) -> Optional[int]:
|
364
335
|
# This can be safely cached as the matryoshka dimension is not expected to change
|
365
336
|
return await get_matryoshka_dimension(kbid, vectorset)
|
366
337
|
|
@@ -221,11 +221,12 @@ def _parse_relation_query(
|
|
221
221
|
def _set_node_to_pb(node: graph_requests.GraphNode, pb: nodereader_pb2.GraphQuery.Node):
|
222
222
|
if node.value is not None:
|
223
223
|
pb.value = node.value
|
224
|
-
if node.match == graph_requests.
|
225
|
-
pb.
|
224
|
+
if node.match == graph_requests.NodeMatchKindName.EXACT:
|
225
|
+
pb.exact.kind = nodereader_pb2.GraphQuery.Node.MatchLocation.FULL
|
226
226
|
|
227
|
-
elif node.match == graph_requests.
|
228
|
-
pb.
|
227
|
+
elif node.match == graph_requests.NodeMatchKindName.FUZZY:
|
228
|
+
pb.fuzzy.kind = nodereader_pb2.GraphQuery.Node.MatchLocation.PREFIX
|
229
|
+
pb.fuzzy.distance = 1
|
229
230
|
|
230
231
|
else: # pragma: nocover
|
231
232
|
# This is a trick so mypy generates an error if this branch can be reached,
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: nucliadb
|
3
|
-
Version: 6.3.4.
|
3
|
+
Version: 6.3.4.post3823
|
4
4
|
Summary: NucliaDB
|
5
5
|
Author-email: Nuclia <nucliadb@nuclia.com>
|
6
6
|
License: AGPL
|
@@ -20,11 +20,11 @@ Classifier: Programming Language :: Python :: 3.12
|
|
20
20
|
Classifier: Programming Language :: Python :: 3 :: Only
|
21
21
|
Requires-Python: <4,>=3.9
|
22
22
|
Description-Content-Type: text/markdown
|
23
|
-
Requires-Dist: nucliadb-telemetry[all]>=6.3.4.
|
24
|
-
Requires-Dist: nucliadb-utils[cache,fastapi,storages]>=6.3.4.
|
25
|
-
Requires-Dist: nucliadb-protos>=6.3.4.
|
26
|
-
Requires-Dist: nucliadb-models>=6.3.4.
|
27
|
-
Requires-Dist: nidx-protos>=6.3.4.
|
23
|
+
Requires-Dist: nucliadb-telemetry[all]>=6.3.4.post3823
|
24
|
+
Requires-Dist: nucliadb-utils[cache,fastapi,storages]>=6.3.4.post3823
|
25
|
+
Requires-Dist: nucliadb-protos>=6.3.4.post3823
|
26
|
+
Requires-Dist: nucliadb-models>=6.3.4.post3823
|
27
|
+
Requires-Dist: nidx-protos>=6.3.4.post3823
|
28
28
|
Requires-Dist: nucliadb-admin-assets>=1.0.0.post1224
|
29
29
|
Requires-Dist: nuclia-models>=0.24.2
|
30
30
|
Requires-Dist: uvicorn
|
@@ -141,7 +141,7 @@ nucliadb/ingest/fields/text.py,sha256=tFvSQJAe0W7ePpp2_WDfLiE2yglR1OTU0Zht9acvOF
|
|
141
141
|
nucliadb/ingest/orm/__init__.py,sha256=cp15ZcFnHvpcu_5-aK2A4uUyvuZVV_MJn4bIXMa20ks,835
|
142
142
|
nucliadb/ingest/orm/brain.py,sha256=A8H1J7Bo95sNzDgYr0_UNoemQhWOFEFz9UlYfs6ug-8,29407
|
143
143
|
nucliadb/ingest/orm/broker_message.py,sha256=XWaiZgDOz94NPOPT-hqbRr5ZkpVimUw6PjUJNftfoVw,7514
|
144
|
-
nucliadb/ingest/orm/entities.py,sha256=
|
144
|
+
nucliadb/ingest/orm/entities.py,sha256=a-aYuKBUQhxDKFtXOzTAkLlY_t2JiTfaptw2vt3AQDQ,14915
|
145
145
|
nucliadb/ingest/orm/exceptions.py,sha256=k4Esv4NtL4TrGTcsQpwrSfDhPQpiYcRbB1SpYmBX5MY,1432
|
146
146
|
nucliadb/ingest/orm/knowledgebox.py,sha256=Bfb4-MIQWlaJrQAUDbgs_iIsXCYjS7s5YiiGl_Jb4jo,23887
|
147
147
|
nucliadb/ingest/orm/metrics.py,sha256=OkwMSPKLZcKba0ZTwtTiIxwBgaLMX5ydhGieKvi2y7E,1096
|
@@ -229,10 +229,10 @@ nucliadb/search/search/filters.py,sha256=1MkHlJjAQqoRCj7e5cEzK2HvBxGLE17I_omsjik
|
|
229
229
|
nucliadb/search/search/find.py,sha256=pjc-i55j_p_F1H0La4qc9slZSl_gICoFzl3fy6FLYTM,10314
|
230
230
|
nucliadb/search/search/find_merge.py,sha256=3FnzKFEnVemg6FO_6zveulbAU7klvsiPEBvLrpBBMg8,17450
|
231
231
|
nucliadb/search/search/graph_merge.py,sha256=OiUNiXOWwrUVKqStuRcoUJwvDbDYamqIgiAy_FwPdMI,3405
|
232
|
-
nucliadb/search/search/graph_strategy.py,sha256=
|
232
|
+
nucliadb/search/search/graph_strategy.py,sha256=SPJdDHQcTFsNb1IEWdWzklC5j1Vv9igibo0dYQAgcy0,33113
|
233
233
|
nucliadb/search/search/hydrator.py,sha256=-R37gCrGxkyaiHQalnTWHNG_FCx11Zucd7qA1vQCxuw,6985
|
234
234
|
nucliadb/search/search/ingestion_agents.py,sha256=NeJr4EEX-bvFFMGvXOOwLv8uU7NuQ-ntJnnrhnKfMzY,3174
|
235
|
-
nucliadb/search/search/merge.py,sha256=
|
235
|
+
nucliadb/search/search/merge.py,sha256=fh5WnA_xnXp-Iiq5Cud9hIGole7_0OW2b3Oymk32D6Y,22689
|
236
236
|
nucliadb/search/search/metrics.py,sha256=GGGtXHLhK79_ESV277xkBVjcaMURXHCxYG0EdGamUd8,2886
|
237
237
|
nucliadb/search/search/paragraphs.py,sha256=pNAEiYqJGGUVcEf7xf-PFMVqz0PX4Qb-WNG-_zPGN2o,7799
|
238
238
|
nucliadb/search/search/pgcatalog.py,sha256=s_J98fsX_RuFXwpejpkGqG-tD9ELuzz4YQ6U3ew5h2g,9313
|
@@ -251,14 +251,14 @@ nucliadb/search/search/chat/prompt.py,sha256=Jnja-Ss7skgnnDY8BymVfdeYsFPnIQFL8tE
|
|
251
251
|
nucliadb/search/search/chat/query.py,sha256=0IoeW-JNaRBe2d9C3bXNfkYpzmsN_IIg3U4Vqb8eOEk,16485
|
252
252
|
nucliadb/search/search/query_parser/__init__.py,sha256=cp15ZcFnHvpcu_5-aK2A4uUyvuZVV_MJn4bIXMa20ks,835
|
253
253
|
nucliadb/search/search/query_parser/exceptions.py,sha256=szAOXUZ27oNY-OSa9t2hQ5HHkQQC0EX1FZz_LluJHJE,1224
|
254
|
-
nucliadb/search/search/query_parser/fetcher.py,sha256=
|
254
|
+
nucliadb/search/search/query_parser/fetcher.py,sha256=vrPgPnebWlrbx9fcelw7eHayEDptxnm9BP1F9LAEMws,15307
|
255
255
|
nucliadb/search/search/query_parser/filter_expression.py,sha256=rws5vsKTofX2iMUK4yvjmLZFxtcbWbyhIcwen4j0rQg,6578
|
256
256
|
nucliadb/search/search/query_parser/models.py,sha256=7czH-jHskl9axEnZV5XnQY8cyN_fs14Cpivzd5aaSxc,2686
|
257
257
|
nucliadb/search/search/query_parser/old_filters.py,sha256=-zbfN-RsXoj_DRjh3Lfp-wShwFXgkISawzVptVzja-A,9071
|
258
258
|
nucliadb/search/search/query_parser/parsers/__init__.py,sha256=ySCNSdbesLXGZyR88919njulA6UE10_3PhqMG_Yj1o4,1034
|
259
259
|
nucliadb/search/search/query_parser/parsers/catalog.py,sha256=XdBiTweGTQkj8m_V_i2xbwp7P5pPO8K1Tud692XKhMw,7149
|
260
260
|
nucliadb/search/search/query_parser/parsers/find.py,sha256=q3wH_i0DGceeKckYEH3c5MqM5EvRiMCL7r-6nCAId9Q,4666
|
261
|
-
nucliadb/search/search/query_parser/parsers/graph.py,sha256=
|
261
|
+
nucliadb/search/search/query_parser/parsers/graph.py,sha256=QJs-pybNXPsMSEkIHctb0Q0xQG-aArks8BtUxbJL5rU,9386
|
262
262
|
nucliadb/standalone/__init__.py,sha256=cp15ZcFnHvpcu_5-aK2A4uUyvuZVV_MJn4bIXMa20ks,835
|
263
263
|
nucliadb/standalone/api_router.py,sha256=hgq9FXpihzgjHkwcVGfGCSwyXy67fqXTfLFHuINzIi0,5567
|
264
264
|
nucliadb/standalone/app.py,sha256=mAApNK_iVsQgJyd-mtwCeZq5csSimwnXmlQGH9a70pE,5586
|
@@ -354,8 +354,8 @@ nucliadb/writer/tus/local.py,sha256=7jYa_w9b-N90jWgN2sQKkNcomqn6JMVBOVeDOVYJHto,
|
|
354
354
|
nucliadb/writer/tus/s3.py,sha256=vF0NkFTXiXhXq3bCVXXVV-ED38ECVoUeeYViP8uMqcU,8357
|
355
355
|
nucliadb/writer/tus/storage.py,sha256=ToqwjoYnjI4oIcwzkhha_MPxi-k4Jk3Lt55zRwaC1SM,2903
|
356
356
|
nucliadb/writer/tus/utils.py,sha256=MSdVbRsRSZVdkaum69_0wku7X3p5wlZf4nr6E0GMKbw,2556
|
357
|
-
nucliadb-6.3.4.
|
358
|
-
nucliadb-6.3.4.
|
359
|
-
nucliadb-6.3.4.
|
360
|
-
nucliadb-6.3.4.
|
361
|
-
nucliadb-6.3.4.
|
357
|
+
nucliadb-6.3.4.post3823.dist-info/METADATA,sha256=id3yZ3Ww5cXYXQ1Y9VWVEhl_7cyP3m9RDTwGYxNH5Zc,4291
|
358
|
+
nucliadb-6.3.4.post3823.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
359
|
+
nucliadb-6.3.4.post3823.dist-info/entry_points.txt,sha256=XqGfgFDuY3zXQc8ewXM2TRVjTModIq851zOsgrmaXx4,1268
|
360
|
+
nucliadb-6.3.4.post3823.dist-info/top_level.txt,sha256=hwYhTVnX7jkQ9gJCkVrbqEG1M4lT2F_iPQND1fCzF80,20
|
361
|
+
nucliadb-6.3.4.post3823.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|