nucliadb 6.3.1.post3577__py3-none-any.whl → 6.3.1.post3590__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.
@@ -30,7 +30,6 @@ from nucliadb.backups.const import (
30
30
  )
31
31
  from nucliadb.backups.models import BackupMetadata, CreateBackupRequest
32
32
  from nucliadb.backups.settings import settings
33
- from nucliadb.backups.utils import exists_in_storge
34
33
  from nucliadb.common import datamanagers
35
34
  from nucliadb.common.context import ApplicationContext
36
35
  from nucliadb.export_import.utils import (
@@ -261,7 +260,7 @@ async def delete_metadata(context: ApplicationContext, kbid: str, backup_id: str
261
260
 
262
261
 
263
262
  async def exists_cf(context: ApplicationContext, cf: resources_pb2.CloudFile) -> bool:
264
- return await exists_in_storge(context.blob_storage, cf.bucket_name, cf.uri)
263
+ return await context.blob_storage.exists_object(bucket=cf.bucket_name, key=cf.uri)
265
264
 
266
265
 
267
266
  async def upload_to_bucket(context: ApplicationContext, bytes_iterator: AsyncIterator[bytes], key: str):
nucliadb/backups/utils.py CHANGED
@@ -24,12 +24,7 @@ from nucliadb_utils.storages.storage import Storage
24
24
 
25
25
 
26
26
  async def exists_backup(storage: Storage, backup_id: str) -> bool:
27
- return await exists_in_storge(
28
- storage, settings.backups_bucket, StorageKeys.BACKUP_PREFIX.format(backup_id=backup_id)
27
+ # As the labels file is always created, we use it to check if the backup exists
28
+ return await storage.exists_object(
29
+ settings.backups_bucket, StorageKeys.LABELS.format(backup_id=backup_id)
29
30
  )
30
-
31
-
32
- async def exists_in_storge(storage: Storage, bucket: str, key: str) -> bool:
33
- async for _ in storage.iterate_objects(bucket=bucket, prefix=key):
34
- return True
35
- return False
nucliadb/common/nidx.py CHANGED
@@ -262,6 +262,7 @@ class NodeNidxAdapter:
262
262
  # Searcher methods
263
263
  self.Search = searcher_client.Search
264
264
  self.Suggest = searcher_client.Suggest
265
+ self.GraphSearch = searcher_client.GraphSearch
265
266
  self.Paragraphs = searcher_client.Paragraphs
266
267
  self.Documents = searcher_client.Documents
267
268
 
@@ -17,16 +17,19 @@
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
- from . import ask # noqa
21
- from . import catalog # noqa
22
- from . import feedback # noqa
23
- from . import find # noqa
24
- from . import knowledgebox # noqa
25
- from . import predict_proxy # noqa
26
- from . import search # noqa
27
- from . import suggest # noqa
28
- from . import summarize # noqa
29
- from .resource import ask as ask_resource # noqa
30
- from .resource import search as search_resource # noqa
31
- from .resource import ingestion_agents as ingestion_agents_resource # noqa
32
- from .router import api # noqa
20
+ from . import ( # noqa: F401
21
+ ask,
22
+ catalog,
23
+ feedback,
24
+ find,
25
+ graph,
26
+ knowledgebox,
27
+ predict_proxy,
28
+ search,
29
+ suggest,
30
+ summarize,
31
+ )
32
+ from .resource import ask as ask_resource # noqa: F401
33
+ from .resource import ingestion_agents as ingestion_agents_resource # noqa: F401
34
+ from .resource import search as search_resource # noqa: F401
35
+ from .router import api # noqa: F401
@@ -36,7 +36,7 @@ from nucliadb.search.search import cache
36
36
  from nucliadb.search.search.exceptions import InvalidQueryError
37
37
  from nucliadb.search.search.merge import fetch_resources
38
38
  from nucliadb.search.search.pgcatalog import pgcatalog_search
39
- from nucliadb.search.search.query_parser.catalog import parse_catalog
39
+ from nucliadb.search.search.query_parser.parsers import parse_catalog
40
40
  from nucliadb.search.search.utils import (
41
41
  maybe_log_request_payload,
42
42
  )
@@ -0,0 +1,130 @@
1
+ # Copyright (C) 2021 Bosutech XXI S.L.
2
+ #
3
+ # nucliadb is offered under the AGPL v3.0 and as commercial software.
4
+ # For commercial licensing, contact us at info@nuclia.com.
5
+ #
6
+ # AGPL:
7
+ # This program is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Affero General Public License as
9
+ # published by the Free Software Foundation, either version 3 of the
10
+ # License, or (at your option) any later version.
11
+ #
12
+ # This program is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Affero General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Affero General Public License
18
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
19
+ #
20
+ from fastapi import Header, Request, Response
21
+ from fastapi_versioning import version
22
+
23
+ from nucliadb.search.api.v1.router import KB_PREFIX, api
24
+ from nucliadb.search.requesters.utils import Method, node_query
25
+ from nucliadb.search.search.graph_merge import (
26
+ build_graph_nodes_response,
27
+ build_graph_relations_response,
28
+ build_graph_response,
29
+ )
30
+ from nucliadb.search.search.query_parser.parsers import (
31
+ parse_graph_node_search,
32
+ parse_graph_relation_search,
33
+ parse_graph_search,
34
+ )
35
+ from nucliadb_models.graph.requests import (
36
+ GraphNodesSearchRequest,
37
+ GraphRelationsSearchRequest,
38
+ GraphSearchRequest,
39
+ )
40
+ from nucliadb_models.graph.responses import (
41
+ GraphNodesSearchResponse,
42
+ GraphRelationsSearchResponse,
43
+ GraphSearchResponse,
44
+ )
45
+ from nucliadb_models.resource import NucliaDBRoles
46
+ from nucliadb_models.search import (
47
+ NucliaDBClientType,
48
+ )
49
+ from nucliadb_utils.authentication import requires
50
+
51
+
52
+ @api.post(
53
+ f"/{KB_PREFIX}/{{kbid}}/graph",
54
+ status_code=200,
55
+ summary="Search Knowledge Box graph",
56
+ description="Search on the Knowledge Box graph and retrieve triplets of vertex-edge-vertex",
57
+ response_model_exclude_unset=True,
58
+ include_in_schema=False,
59
+ tags=["Search"],
60
+ )
61
+ @requires(NucliaDBRoles.READER)
62
+ @version(1)
63
+ async def graph_search_knowledgebox(
64
+ request: Request,
65
+ response: Response,
66
+ kbid: str,
67
+ item: GraphSearchRequest,
68
+ x_ndb_client: NucliaDBClientType = Header(NucliaDBClientType.API),
69
+ x_nucliadb_user: str = Header(""),
70
+ x_forwarded_for: str = Header(""),
71
+ ) -> GraphSearchResponse:
72
+ pb_query = parse_graph_search(item)
73
+
74
+ results, _, _ = await node_query(kbid, Method.GRAPH, pb_query)
75
+
76
+ return build_graph_response(results)
77
+
78
+
79
+ @api.post(
80
+ f"/{KB_PREFIX}/{{kbid}}/graph/nodes",
81
+ status_code=200,
82
+ summary="Search Knowledge Box graph nodes",
83
+ description="Search on the Knowledge Box graph and retrieve nodes (vertices)",
84
+ response_model_exclude_unset=True,
85
+ include_in_schema=False,
86
+ tags=["Search"],
87
+ )
88
+ @requires(NucliaDBRoles.READER)
89
+ @version(1)
90
+ async def graph_nodes_search_knowledgebox(
91
+ request: Request,
92
+ response: Response,
93
+ kbid: str,
94
+ item: GraphNodesSearchRequest,
95
+ x_ndb_client: NucliaDBClientType = Header(NucliaDBClientType.API),
96
+ x_nucliadb_user: str = Header(""),
97
+ x_forwarded_for: str = Header(""),
98
+ ) -> GraphNodesSearchResponse:
99
+ pb_query = parse_graph_node_search(item)
100
+
101
+ results, _, _ = await node_query(kbid, Method.GRAPH, pb_query)
102
+
103
+ return build_graph_nodes_response(results)
104
+
105
+
106
+ @api.post(
107
+ f"/{KB_PREFIX}/{{kbid}}/graph/relations",
108
+ status_code=200,
109
+ summary="Search Knowledge Box graph relations",
110
+ description="Search on the Knowledge Box graph and retrieve relations (edges)",
111
+ response_model_exclude_unset=True,
112
+ include_in_schema=False,
113
+ tags=["Search"],
114
+ )
115
+ @requires(NucliaDBRoles.READER)
116
+ @version(1)
117
+ async def graph_relations_search_knowledgebox(
118
+ request: Request,
119
+ response: Response,
120
+ kbid: str,
121
+ item: GraphRelationsSearchRequest,
122
+ x_ndb_client: NucliaDBClientType = Header(NucliaDBClientType.API),
123
+ x_nucliadb_user: str = Header(""),
124
+ x_forwarded_for: str = Header(""),
125
+ ) -> GraphRelationsSearchResponse:
126
+ pb_query = parse_graph_relation_search(item)
127
+
128
+ results, _, _ = await node_query(kbid, Method.GRAPH, pb_query)
129
+
130
+ return build_graph_relations_response(results)
@@ -33,11 +33,14 @@ from nucliadb.common.cluster.exceptions import ShardsNotFound
33
33
  from nucliadb.common.cluster.utils import get_shard_manager
34
34
  from nucliadb.search import logger
35
35
  from nucliadb.search.search.shards import (
36
+ graph_search_shard,
36
37
  query_shard,
37
38
  suggest_shard,
38
39
  )
39
40
  from nucliadb.search.settings import settings
40
41
  from nucliadb_protos.nodereader_pb2 import (
42
+ GraphSearchRequest,
43
+ GraphSearchResponse,
41
44
  SearchRequest,
42
45
  SearchResponse,
43
46
  SuggestRequest,
@@ -50,19 +53,22 @@ from nucliadb_telemetry import errors
50
53
  class Method(Enum):
51
54
  SEARCH = auto()
52
55
  SUGGEST = auto()
56
+ GRAPH = auto()
53
57
 
54
58
 
55
59
  METHODS = {
56
60
  Method.SEARCH: query_shard,
57
61
  Method.SUGGEST: suggest_shard,
62
+ Method.GRAPH: graph_search_shard,
58
63
  }
59
64
 
60
- REQUEST_TYPE = Union[SuggestRequest, SearchRequest]
65
+ REQUEST_TYPE = Union[SuggestRequest, SearchRequest, GraphSearchRequest]
61
66
 
62
67
  T = TypeVar(
63
68
  "T",
64
69
  SuggestResponse,
65
70
  SearchResponse,
71
+ GraphSearchResponse,
66
72
  )
67
73
 
68
74
 
@@ -84,6 +90,15 @@ async def node_query(
84
90
  ) -> tuple[list[SearchResponse], bool, list[tuple[AbstractIndexNode, str]]]: ...
85
91
 
86
92
 
93
+ @overload
94
+ async def node_query(
95
+ kbid: str,
96
+ method: Method,
97
+ pb_query: GraphSearchRequest,
98
+ timeout: Optional[float] = None,
99
+ ) -> tuple[list[GraphSearchResponse], bool, list[tuple[AbstractIndexNode, str]]]: ...
100
+
101
+
87
102
  async def node_query(
88
103
  kbid: str,
89
104
  method: Method,
@@ -40,7 +40,7 @@ from nucliadb.search.search.metrics import (
40
40
  )
41
41
  from nucliadb.search.search.query import QueryParser
42
42
  from nucliadb.search.search.query_parser.old_filters import OldFilterParams
43
- from nucliadb.search.search.query_parser.parser import parse_find
43
+ from nucliadb.search.search.query_parser.parsers import parse_find
44
44
  from nucliadb.search.search.rank_fusion import (
45
45
  RankFusionAlgorithm,
46
46
  get_rank_fusion,
@@ -0,0 +1,90 @@
1
+ # Copyright (C) 2021 Bosutech XXI S.L.
2
+ #
3
+ # nucliadb is offered under the AGPL v3.0 and as commercial software.
4
+ # For commercial licensing, contact us at info@nuclia.com.
5
+ #
6
+ # AGPL:
7
+ # This program is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Affero General Public License as
9
+ # published by the Free Software Foundation, either version 3 of the
10
+ # License, or (at your option) any later version.
11
+ #
12
+ # This program is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Affero General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Affero General Public License
18
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
19
+ #
20
+
21
+
22
+ from nucliadb.common.models_utils.from_proto import RelationNodeTypePbMap
23
+ from nucliadb_models.graph import responses as graph_responses
24
+ from nucliadb_models.graph.responses import (
25
+ GraphNodesSearchResponse,
26
+ GraphRelationsSearchResponse,
27
+ GraphSearchResponse,
28
+ )
29
+ from nucliadb_protos import nodereader_pb2
30
+
31
+
32
+ def build_graph_response(results: list[nodereader_pb2.GraphSearchResponse]) -> GraphSearchResponse:
33
+ paths = []
34
+ for shard_results in results:
35
+ for pb_path in shard_results.graph:
36
+ source = shard_results.nodes[pb_path.source]
37
+ relation = shard_results.relations[pb_path.relation]
38
+ destination = shard_results.nodes[pb_path.destination]
39
+
40
+ path = graph_responses.GraphPath(
41
+ source=graph_responses.GraphNode(
42
+ value=source.value,
43
+ type=RelationNodeTypePbMap[source.ntype],
44
+ group=source.subtype,
45
+ ),
46
+ relation=graph_responses.GraphRelation(
47
+ label=relation.label,
48
+ ),
49
+ destination=graph_responses.GraphNode(
50
+ value=destination.value,
51
+ type=RelationNodeTypePbMap[destination.ntype],
52
+ group=destination.subtype,
53
+ ),
54
+ )
55
+ paths.append(path)
56
+
57
+ response = GraphSearchResponse(paths=paths)
58
+ return response
59
+
60
+
61
+ def build_graph_nodes_response(
62
+ results: list[nodereader_pb2.GraphSearchResponse],
63
+ ) -> GraphNodesSearchResponse:
64
+ nodes = []
65
+ for shard_results in results:
66
+ for node in shard_results.nodes:
67
+ nodes.append(
68
+ graph_responses.GraphNode(
69
+ value=node.value,
70
+ type=RelationNodeTypePbMap[node.ntype],
71
+ group=node.subtype,
72
+ )
73
+ )
74
+ response = GraphNodesSearchResponse(nodes=nodes)
75
+ return response
76
+
77
+
78
+ def build_graph_relations_response(
79
+ results: list[nodereader_pb2.GraphSearchResponse],
80
+ ) -> GraphRelationsSearchResponse:
81
+ relations = []
82
+ for shard_results in results:
83
+ for relation in shard_results.relations:
84
+ relations.append(
85
+ graph_responses.GraphRelation(
86
+ label=relation.label,
87
+ )
88
+ )
89
+ response = GraphRelationsSearchResponse(relations=relations)
90
+ return response
@@ -111,7 +111,7 @@ def _convert_date_filter(date: CatalogExpression.Date, filter_params: dict[str,
111
111
  raise ValueError(f"Invalid date operator")
112
112
 
113
113
 
114
- def _prepare_query(catalog_query: CatalogQuery):
114
+ def _prepare_query_filters(catalog_query: CatalogQuery) -> tuple[str, dict[str, Any]]:
115
115
  filter_sql = ["kbid = %(kbid)s"]
116
116
  filter_params: dict[str, Any] = {"kbid": catalog_query.kbid}
117
117
 
@@ -127,7 +127,17 @@ def _prepare_query(catalog_query: CatalogQuery):
127
127
  if catalog_query.filters:
128
128
  filter_sql.append(_convert_filter(catalog_query.filters, filter_params))
129
129
 
130
- order_sql = ""
130
+ return (
131
+ f"SELECT * FROM catalog WHERE {' AND '.join(filter_sql)}",
132
+ filter_params,
133
+ )
134
+
135
+
136
+ def _prepare_query(catalog_query: CatalogQuery) -> tuple[str, dict[str, Any]]:
137
+ # Base query with all the filters
138
+ query, filter_params = _prepare_query_filters(catalog_query)
139
+
140
+ # Sort
131
141
  if catalog_query.sort:
132
142
  if catalog_query.sort.field == SortField.CREATED:
133
143
  order_field = "created_at"
@@ -144,12 +154,15 @@ def _prepare_query(catalog_query: CatalogQuery):
144
154
  else:
145
155
  order_dir = "DESC"
146
156
 
147
- order_sql = f" ORDER BY {order_field} {order_dir}"
157
+ query += f" ORDER BY {order_field} {order_dir}"
148
158
 
149
- return (
150
- f"SELECT * FROM catalog WHERE {' AND '.join(filter_sql)}{order_sql}",
151
- filter_params,
152
- )
159
+ # Pagination
160
+ offset = catalog_query.page_size * catalog_query.page_number
161
+ query += f" LIMIT %(page_size)s OFFSET %(offset)s"
162
+ filter_params["page_size"] = catalog_query.page_size
163
+ filter_params["offset"] = offset
164
+
165
+ return query, filter_params
153
166
 
154
167
 
155
168
  def _pg_driver() -> PGDriver:
@@ -159,7 +172,7 @@ def _pg_driver() -> PGDriver:
159
172
  @observer.wrap({"op": "search"})
160
173
  async def pgcatalog_search(catalog_query: CatalogQuery) -> Resources:
161
174
  # Prepare SQL query
162
- query, query_params = _prepare_query(catalog_query)
175
+ query, query_params = _prepare_query_filters(catalog_query)
163
176
 
164
177
  async with _pg_driver()._get_connection() as conn, conn.cursor(row_factory=dict_row) as cur:
165
178
  facets = {}
@@ -210,15 +223,8 @@ async def pgcatalog_search(catalog_query: CatalogQuery) -> Resources:
210
223
 
211
224
  # Query
212
225
  with observer({"op": "query"}):
213
- offset = catalog_query.page_size * catalog_query.page_number
214
- await cur.execute(
215
- f"{query} LIMIT %(page_size)s OFFSET %(offset)s",
216
- {
217
- **query_params,
218
- "page_size": catalog_query.page_size,
219
- "offset": offset,
220
- },
221
- )
226
+ query, query_params = _prepare_query(catalog_query)
227
+ await cur.execute(query, query_params)
222
228
  data = await cur.fetchall()
223
229
 
224
230
  return Resources(
@@ -237,6 +243,6 @@ async def pgcatalog_search(catalog_query: CatalogQuery) -> Resources:
237
243
  total=total,
238
244
  page_number=catalog_query.page_number,
239
245
  page_size=catalog_query.page_size,
240
- next_page=(offset + len(data) < total),
246
+ next_page=(catalog_query.page_size * catalog_query.page_number + len(data) < total),
241
247
  min_score=0,
242
248
  )
@@ -28,6 +28,7 @@ from pydantic import (
28
28
  )
29
29
 
30
30
  from nucliadb_models import search as search_models
31
+ from nucliadb_protos import nodereader_pb2
31
32
 
32
33
  ### Retrieval
33
34
 
@@ -101,3 +102,11 @@ class CatalogQuery(BaseModel):
101
102
  faceted: list[str]
102
103
  page_size: int
103
104
  page_number: int
105
+
106
+
107
+ ### Graph
108
+
109
+
110
+ # Right now, we don't need a more generic model for graph queries, we can
111
+ # directly use the protobuffer directly
112
+ GraphRetrieval = nodereader_pb2.GraphSearchRequest
@@ -0,0 +1,23 @@
1
+ # Copyright (C) 2021 Bosutech XXI S.L.
2
+ #
3
+ # nucliadb is offered under the AGPL v3.0 and as commercial software.
4
+ # For commercial licensing, contact us at info@nuclia.com.
5
+ #
6
+ # AGPL:
7
+ # This program is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Affero General Public License as
9
+ # published by the Free Software Foundation, either version 3 of the
10
+ # License, or (at your option) any later version.
11
+ #
12
+ # This program is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Affero General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Affero General Public License
18
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
19
+ #
20
+
21
+ from .catalog import parse_catalog # noqa: F401
22
+ from .find import parse_find # noqa: F401
23
+ from .graph import parse_graph_node_search, parse_graph_relation_search, parse_graph_search # noqa: F401
@@ -18,10 +18,10 @@
18
18
  # along with this program. If not, see <http://www.gnu.org/licenses/>.
19
19
  #
20
20
 
21
-
22
21
  from nucliadb.common import datamanagers
23
22
  from nucliadb.search.search.exceptions import InvalidQueryError
24
23
  from nucliadb.search.search.filters import translate_label
24
+ from nucliadb.search.search.query_parser.filter_expression import FacetFilterTypes, facet_from_filter
25
25
  from nucliadb.search.search.query_parser.models import (
26
26
  CatalogExpression,
27
27
  CatalogQuery,
@@ -44,8 +44,6 @@ from nucliadb_models.search import (
44
44
  SortOrder,
45
45
  )
46
46
 
47
- from .filter_expression import FacetFilterTypes, facet_from_filter
48
-
49
47
 
50
48
  async def parse_catalog(kbid: str, item: search_models.CatalogRequest) -> CatalogQuery:
51
49
  has_old_filters = (
@@ -18,7 +18,6 @@
18
18
  # along with this program. If not, see <http://www.gnu.org/licenses/>.
19
19
  #
20
20
 
21
-
22
21
  from pydantic import ValidationError
23
22
 
24
23
  from nucliadb.search.search.query_parser.exceptions import InternalParserError
@@ -0,0 +1,177 @@
1
+ # Copyright (C) 2021 Bosutech XXI S.L.
2
+ #
3
+ # nucliadb is offered under the AGPL v3.0 and as commercial software.
4
+ # For commercial licensing, contact us at info@nuclia.com.
5
+ #
6
+ # AGPL:
7
+ # This program is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Affero General Public License as
9
+ # published by the Free Software Foundation, either version 3 of the
10
+ # License, or (at your option) any later version.
11
+ #
12
+ # This program is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Affero General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Affero General Public License
18
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
19
+ #
20
+
21
+
22
+ from nucliadb.common.models_utils.from_proto import RelationNodeTypeMap
23
+ from nucliadb.search.search.query_parser.models import GraphRetrieval
24
+ from nucliadb_models.graph import requests as graph_requests
25
+ from nucliadb_protos import nodereader_pb2
26
+
27
+
28
+ def parse_graph_search(item: graph_requests.GraphSearchRequest) -> GraphRetrieval:
29
+ pb = nodereader_pb2.GraphSearchRequest()
30
+ pb.query.path.CopyFrom(_parse_path_query(item.query))
31
+ pb.top_k = item.top_k
32
+ return pb
33
+
34
+
35
+ def parse_graph_node_search(item: graph_requests.GraphNodesSearchRequest) -> GraphRetrieval:
36
+ pb = nodereader_pb2.GraphSearchRequest()
37
+ pb.query.path.CopyFrom(_parse_node_query(item.query))
38
+ pb.top_k = item.top_k
39
+ return pb
40
+
41
+
42
+ def parse_graph_relation_search(item: graph_requests.GraphRelationsSearchRequest) -> GraphRetrieval:
43
+ pb = nodereader_pb2.GraphSearchRequest()
44
+ pb.query.path.CopyFrom(_parse_relation_query(item.query))
45
+ pb.top_k = item.top_k
46
+ return pb
47
+
48
+
49
+ def _parse_path_query(expr: graph_requests.GraphPathQuery) -> nodereader_pb2.GraphQuery.PathQuery:
50
+ pb = nodereader_pb2.GraphQuery.PathQuery()
51
+
52
+ if isinstance(expr, graph_requests.And):
53
+ for op in expr.operands:
54
+ pb.bool_and.operands.append(_parse_path_query(op))
55
+
56
+ elif isinstance(expr, graph_requests.Or):
57
+ for op in expr.operands:
58
+ pb.bool_or.operands.append(_parse_path_query(op))
59
+
60
+ elif isinstance(expr, graph_requests.Not):
61
+ pb.bool_not.CopyFrom(_parse_path_query(expr.operand))
62
+
63
+ elif isinstance(expr, graph_requests.GraphPath):
64
+ if expr.source is not None:
65
+ _set_node_to_pb(expr.source, pb.path.source)
66
+
67
+ if expr.destination is not None:
68
+ _set_node_to_pb(expr.destination, pb.path.destination)
69
+
70
+ if expr.relation is not None:
71
+ relation = expr.relation
72
+ if relation.label is not None:
73
+ pb.path.relation.value = relation.label
74
+
75
+ pb.path.undirected = expr.undirected
76
+
77
+ elif isinstance(expr, graph_requests.SourceNode):
78
+ _set_node_to_pb(expr, pb.path.source)
79
+
80
+ elif isinstance(expr, graph_requests.DestinationNode):
81
+ _set_node_to_pb(expr, pb.path.destination)
82
+
83
+ elif isinstance(expr, graph_requests.AnyNode):
84
+ _set_node_to_pb(expr, pb.path.source)
85
+ pb.path.undirected = True
86
+
87
+ elif isinstance(expr, graph_requests.Relation):
88
+ if expr.label is not None:
89
+ pb.path.relation.value = expr.label
90
+
91
+ else: # pragma: nocover
92
+ # This is a trick so mypy generates an error if this branch can be reached,
93
+ # that is, if we are missing some ifs
94
+ _a: int = "a"
95
+
96
+ return pb
97
+
98
+
99
+ def _parse_node_query(expr: graph_requests.GraphNodesQuery) -> nodereader_pb2.GraphQuery.PathQuery:
100
+ pb = nodereader_pb2.GraphQuery.PathQuery()
101
+
102
+ if isinstance(expr, graph_requests.And):
103
+ for op in expr.operands:
104
+ pb.bool_and.operands.append(_parse_node_query(op))
105
+
106
+ elif isinstance(expr, graph_requests.Or):
107
+ for op in expr.operands:
108
+ pb.bool_or.operands.append(_parse_node_query(op))
109
+
110
+ elif isinstance(expr, graph_requests.Not):
111
+ pb.bool_not.CopyFrom(_parse_node_query(expr.operand))
112
+
113
+ elif isinstance(expr, graph_requests.SourceNode):
114
+ _set_node_to_pb(expr, pb.path.source)
115
+
116
+ elif isinstance(expr, graph_requests.DestinationNode):
117
+ _set_node_to_pb(expr, pb.path.destination)
118
+
119
+ elif isinstance(expr, graph_requests.AnyNode):
120
+ _set_node_to_pb(expr, pb.path.source)
121
+ pb.path.undirected = True
122
+
123
+ else: # pragma: nocover
124
+ # This is a trick so mypy generates an error if this branch can be reached,
125
+ # that is, if we are missing some ifs
126
+ _a: int = "a"
127
+
128
+ return pb
129
+
130
+
131
+ def _parse_relation_query(
132
+ expr: graph_requests.GraphRelationsQuery,
133
+ ) -> nodereader_pb2.GraphQuery.PathQuery:
134
+ pb = nodereader_pb2.GraphQuery.PathQuery()
135
+
136
+ if isinstance(expr, graph_requests.And):
137
+ for op in expr.operands:
138
+ pb.bool_and.operands.append(_parse_relation_query(op))
139
+
140
+ elif isinstance(expr, graph_requests.Or):
141
+ for op in expr.operands:
142
+ pb.bool_or.operands.append(_parse_relation_query(op))
143
+
144
+ elif isinstance(expr, graph_requests.Not):
145
+ pb.bool_not.CopyFrom(_parse_relation_query(expr.operand))
146
+
147
+ elif isinstance(expr, graph_requests.Relation):
148
+ if expr.label is not None:
149
+ pb.path.relation.value = expr.label
150
+
151
+ else: # pragma: nocover
152
+ # This is a trick so mypy generates an error if this branch can be reached,
153
+ # that is, if we are missing some ifs
154
+ _a: int = "a"
155
+
156
+ return pb
157
+
158
+
159
+ def _set_node_to_pb(node: graph_requests.GraphNode, pb: nodereader_pb2.GraphQuery.Node):
160
+ if node.value is not None:
161
+ pb.value = node.value
162
+ if node.match == graph_requests.NodeMatchKind.EXACT:
163
+ pb.match_kind = nodereader_pb2.GraphQuery.Node.MatchKind.EXACT
164
+
165
+ elif node.match == graph_requests.NodeMatchKind.FUZZY:
166
+ pb.match_kind = nodereader_pb2.GraphQuery.Node.MatchKind.FUZZY
167
+
168
+ else: # pragma: nocover
169
+ # This is a trick so mypy generates an error if this branch can be reached,
170
+ # that is, if we are missing some ifs
171
+ _a: int = "a"
172
+
173
+ if node.type is not None:
174
+ pb.node_type = RelationNodeTypeMap[node.type]
175
+
176
+ if node.group is not None:
177
+ pb.node_subtype = node.group
@@ -26,6 +26,8 @@ from grpc.aio import AioRpcError
26
26
  from nucliadb.common.cluster.base import AbstractIndexNode
27
27
  from nucliadb_protos.nodereader_pb2 import (
28
28
  GetShardRequest,
29
+ GraphSearchRequest,
30
+ GraphSearchResponse,
29
31
  SearchRequest,
30
32
  SearchResponse,
31
33
  SuggestRequest,
@@ -79,3 +81,16 @@ async def suggest_shard(node: AbstractIndexNode, shard: str, query: SuggestReque
79
81
  req.shard = shard
80
82
  with node_observer({"type": "suggest", "node_id": node.id}):
81
83
  return await node.reader.Suggest(req) # type: ignore
84
+
85
+
86
+ @backoff.on_exception(
87
+ backoff.expo, Exception, jitter=None, factor=0.1, max_tries=3, giveup=should_giveup
88
+ )
89
+ async def graph_search_shard(
90
+ node: AbstractIndexNode, shard: str, query: GraphSearchRequest
91
+ ) -> GraphSearchResponse:
92
+ req = GraphSearchRequest()
93
+ req.CopyFrom(query)
94
+ req.shard = shard
95
+ with node_observer({"type": "graph_search", "node_id": node.id}):
96
+ return await node.reader.GraphSearch(req) # type: ignore
nucliadb/tasks/retries.py CHANGED
@@ -20,7 +20,7 @@
20
20
  import functools
21
21
  import logging
22
22
  from enum import Enum
23
- from typing import Optional
23
+ from typing import Callable, Optional
24
24
 
25
25
  from pydantic import BaseModel
26
26
 
@@ -73,7 +73,8 @@ class TaskRetryHandler:
73
73
  self.kbid = kbid
74
74
  self.task_type = task_type
75
75
  self.task_id = task_id
76
- self.max_retries = max_retries
76
+ # Limit max retries to 50
77
+ self.max_retries = min(max_retries, 50)
77
78
  self.context = context
78
79
 
79
80
  @property
@@ -94,7 +95,7 @@ class TaskRetryHandler:
94
95
  await txn.set(self.metadata_key, metadata.model_dump_json().encode())
95
96
  await txn.commit()
96
97
 
97
- def wrap(self, func):
98
+ def wrap(self, func: Callable) -> Callable:
98
99
  @functools.wraps(func)
99
100
  async def wrapper(*args, **kwargs):
100
101
  func_result = None
@@ -110,7 +111,7 @@ class TaskRetryHandler:
110
111
 
111
112
  if metadata.status in (TaskMetadata.Status.COMPLETED, TaskMetadata.Status.FAILED):
112
113
  logger.info(
113
- f"{self.type} task is {metadata.status.value}. Skipping",
114
+ f"{self.task_type} task is {metadata.status.value}. Skipping",
114
115
  extra={"kbid": self.kbid, "task_type": self.task_type, "task_id": self.task_id},
115
116
  )
116
117
  return
@@ -130,7 +131,7 @@ class TaskRetryHandler:
130
131
  except Exception as ex:
131
132
  metadata.retries += 1
132
133
  metadata.error_messages.append(str(ex))
133
- logger.info(
134
+ logger.exception(
134
135
  f"Task failed. Will be retried",
135
136
  extra={"kbid": self.kbid, "task_type": self.task_type, "task_id": self.task_id},
136
137
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: nucliadb
3
- Version: 6.3.1.post3577
3
+ Version: 6.3.1.post3590
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.1.post3577
24
- Requires-Dist: nucliadb-utils[cache,fastapi,storages]>=6.3.1.post3577
25
- Requires-Dist: nucliadb-protos>=6.3.1.post3577
26
- Requires-Dist: nucliadb-models>=6.3.1.post3577
27
- Requires-Dist: nidx-protos>=6.3.1.post3577
23
+ Requires-Dist: nucliadb-telemetry[all]>=6.3.1.post3590
24
+ Requires-Dist: nucliadb-utils[cache,fastapi,storages]>=6.3.1.post3590
25
+ Requires-Dist: nucliadb-protos>=6.3.1.post3590
26
+ Requires-Dist: nucliadb-models>=6.3.1.post3590
27
+ Requires-Dist: nidx-protos>=6.3.1.post3590
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
@@ -41,19 +41,19 @@ nucliadb/openapi.py,sha256=wDiw0dVEvTpJvbatkJ0JZLkKm9RItZT5PWRHjqRfqTA,2272
41
41
  nucliadb/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
42
42
  nucliadb/backups/__init__.py,sha256=cp15ZcFnHvpcu_5-aK2A4uUyvuZVV_MJn4bIXMa20ks,835
43
43
  nucliadb/backups/const.py,sha256=9vPAhLxQO_gNAjSdPxWuv3V66s9WcdpjOQ89CZlfmuk,1894
44
- nucliadb/backups/create.py,sha256=mvirguMbtxNgSDGG81l0kkgHWJSZPk4GFyra9nAkBZM,11275
44
+ nucliadb/backups/create.py,sha256=w6KpjkTOpIoPVrtOZrxB99oMdWp6jYkyIJ1-qo_k4Mw,11230
45
45
  nucliadb/backups/delete.py,sha256=1rnBhVUGYYZJXSZUrrgYMDZ5NyswEWkIA-G-crRCyHk,2404
46
46
  nucliadb/backups/models.py,sha256=-hITU4Mv6AxePu12toBu_fjpEv6vVGcwNVxV22O9jQA,1273
47
47
  nucliadb/backups/restore.py,sha256=wepEgv4vBN5yeiZU-f17PbuFV4xT4_SVKplNr8xSJrE,10001
48
48
  nucliadb/backups/settings.py,sha256=SyzsInj1BRbBI0atg5IXWbMbOZ_eVg4eSQ3IcnUhCxQ,1357
49
49
  nucliadb/backups/tasks.py,sha256=4_kOVJ2yCwMvDEpzJgTuTt75TNlpq5woyw9sTAcaSkw,4194
50
- nucliadb/backups/utils.py,sha256=b1hi0gEp90tNrWHejNVoUgRpa4D6uKGhbACq0yeLkJY,1375
50
+ nucliadb/backups/utils.py,sha256=_Vogjqcru5oqNZM-bZ0q7Ju79Bv1PD-LVFEa7Z-Q13I,1261
51
51
  nucliadb/common/__init__.py,sha256=cp15ZcFnHvpcu_5-aK2A4uUyvuZVV_MJn4bIXMa20ks,835
52
52
  nucliadb/common/constants.py,sha256=QpigxJh_CtD85Evy0PtV5cVq6x0U_f9xfIcXz1ymkUg,869
53
53
  nucliadb/common/counters.py,sha256=8lOi3A2HeLDDlcNaS2QT1SfD3350VPBjiY3FkmHH1V8,977
54
54
  nucliadb/common/ids.py,sha256=4QjoIofes_vtKj2HsFWZf8VVIVWXxdkYtLpx1n618Us,8239
55
55
  nucliadb/common/locking.py,sha256=RL0CabZVPzxHZyUjYeUyLvsJTm7W3J9o4fEgsY_ufNc,5896
56
- nucliadb/common/nidx.py,sha256=_LoU8D4afEtlW0c3vGUCoatDZvMr0-2l_GtIGap7VxA,10185
56
+ nucliadb/common/nidx.py,sha256=Xuh7qT3fTDiyBlXe40gXtk3URE0EoJHoi0BsSA5fNZU,10240
57
57
  nucliadb/common/cluster/__init__.py,sha256=cp15ZcFnHvpcu_5-aK2A4uUyvuZVV_MJn4bIXMa20ks,835
58
58
  nucliadb/common/cluster/base.py,sha256=kklDqyvsubNX0W494ttl9f3E58lGaX6AXqAd8XX8ZHE,5522
59
59
  nucliadb/common/cluster/exceptions.py,sha256=t7v_l93t44l2tQpdQXgO_w-c4YZRcaayOz1A2i0w4RQ,1258
@@ -197,11 +197,12 @@ nucliadb/search/run.py,sha256=aFb-CXRi_C8YMpP_ivNj8KW1BYhADj88y8K9Lr_nUPI,1402
197
197
  nucliadb/search/settings.py,sha256=vem3EcyYlTPSim0kEK-xe-erF4BZg0CT_LAb8ZRQAE8,1684
198
198
  nucliadb/search/utilities.py,sha256=9SsRDw0rJVXVoLBfF7rBb6q080h-thZc7u8uRcTiBeY,1037
199
199
  nucliadb/search/api/__init__.py,sha256=cp15ZcFnHvpcu_5-aK2A4uUyvuZVV_MJn4bIXMa20ks,835
200
- nucliadb/search/api/v1/__init__.py,sha256=8w6VhZ5rbzX1xLSXr336d2IE-O0dQiv-ba6UYdRKnHA,1325
200
+ nucliadb/search/api/v1/__init__.py,sha256=DH16OYnw9jQ38OpKlmdXeoq2j40ZPXZRtGvClKOkMhw,1239
201
201
  nucliadb/search/api/v1/ask.py,sha256=F2dR3-swb3Xz8MfZPYL3G65KY2R_mgef4YVBbu8kLi4,4352
202
- nucliadb/search/api/v1/catalog.py,sha256=IyBkq99CND1kFelsedJiQaSD8GOPGBJpcKuw1Z6jB9E,7709
202
+ nucliadb/search/api/v1/catalog.py,sha256=MRiuawjKoWXdd-tptw8r8HyBhZ1JgdUYpau__69oij0,7709
203
203
  nucliadb/search/api/v1/feedback.py,sha256=kNLc4dHz2SXHzV0PwC1WiRAwY88fDptPcP-kO0q-FrQ,2620
204
204
  nucliadb/search/api/v1/find.py,sha256=l2dRg0eYngq52vyn9_z9iK7bdO7ufHQDnJWBZgMVrqY,9628
205
+ nucliadb/search/api/v1/graph.py,sha256=5APs0-W-jNQfH-mRLrdRkk6B_mnsJxLb68t0NE_KZUk,4238
205
206
  nucliadb/search/api/v1/knowledgebox.py,sha256=rWhx3PYWryingu19qwwFDbVvVYynq5Ky23FSlzmTutQ,8721
206
207
  nucliadb/search/api/v1/predict_proxy.py,sha256=QrGzo0hKjtmyGZ6pjlJHYAh4hxwVUIOTcVcerRCw7eE,3047
207
208
  nucliadb/search/api/v1/router.py,sha256=mtT07rBZcVfpa49doaw9b1tj3sdi3qLH0gn9Io6NYM0,988
@@ -215,27 +216,28 @@ nucliadb/search/api/v1/resource/ingestion_agents.py,sha256=fqqRCd8Wc9GciS5P98lcn
215
216
  nucliadb/search/api/v1/resource/search.py,sha256=s_si6iilqhmopEQ5GG5c7C_4QV3X8QneQyS5zP0d22I,5228
216
217
  nucliadb/search/api/v1/resource/utils.py,sha256=-NjZqAQtFEXKpIh8ui5S26ItnJ5rzmmG0BHxGSS9QPw,1141
217
218
  nucliadb/search/requesters/__init__.py,sha256=itSI7dtTwFP55YMX4iK7JzdMHS5CQVUiB1XzQu4UBh8,833
218
- nucliadb/search/requesters/utils.py,sha256=qL81UVPNgBftUMLpcxIYVr7ILsMqpKCo-9SY2EvAaXw,6681
219
+ nucliadb/search/requesters/utils.py,sha256=BIJjfjJt3qClA6XRtqA7E5am5Re29CaY_R6QOuTG-24,7082
219
220
  nucliadb/search/search/__init__.py,sha256=cp15ZcFnHvpcu_5-aK2A4uUyvuZVV_MJn4bIXMa20ks,835
220
221
  nucliadb/search/search/cache.py,sha256=n9vkN6Y6Xnr2RBJyoH0WzjzGTJOMfKekU9tfPTWWCPc,6810
221
222
  nucliadb/search/search/cut.py,sha256=ytY0_GY7ocNjfxTb4aosxEp4ZfhQNDP--JkhEMGD298,1153
222
223
  nucliadb/search/search/exceptions.py,sha256=klGLgAGGrXcSGix_W6418ZBMqDchAIGjN77ofkOScEI,1039
223
224
  nucliadb/search/search/fetch.py,sha256=XJHIFnZmXM_8Kb37lb4lg1GYG7cZ1plT-qAIb_QziX4,6184
224
225
  nucliadb/search/search/filters.py,sha256=1MkHlJjAQqoRCj7e5cEzK2HvBxGLE17I_omsjiklbtw,6476
225
- nucliadb/search/search/find.py,sha256=jQZOqu8VeX8k3ELV8bLK4TwUUjGrvmubouxvO1IvJV0,10236
226
+ nucliadb/search/search/find.py,sha256=p7Odx3hjPwTsHEhQrVYsR_ufq0meMmCnQV0YihfOmlg,10237
226
227
  nucliadb/search/search/find_merge.py,sha256=3FnzKFEnVemg6FO_6zveulbAU7klvsiPEBvLrpBBMg8,17450
228
+ nucliadb/search/search/graph_merge.py,sha256=7LzzU09HCFu6wm3LfgJ3Lm6Uuh_qPDmM2tWZS-fHmw8,3250
227
229
  nucliadb/search/search/graph_strategy.py,sha256=gisL2GpbSIa_SucyOwEt7TWdqURyAQqxvD_-PkXQct8,32339
228
230
  nucliadb/search/search/hydrator.py,sha256=-R37gCrGxkyaiHQalnTWHNG_FCx11Zucd7qA1vQCxuw,6985
229
231
  nucliadb/search/search/ingestion_agents.py,sha256=NeJr4EEX-bvFFMGvXOOwLv8uU7NuQ-ntJnnrhnKfMzY,3174
230
232
  nucliadb/search/search/merge.py,sha256=aUn6f5XnwWzUFhVC6uBqHE8NKdlfgw_xcTo57rS23U8,22950
231
233
  nucliadb/search/search/metrics.py,sha256=GGGtXHLhK79_ESV277xkBVjcaMURXHCxYG0EdGamUd8,2886
232
234
  nucliadb/search/search/paragraphs.py,sha256=pNAEiYqJGGUVcEf7xf-PFMVqz0PX4Qb-WNG-_zPGN2o,7799
233
- nucliadb/search/search/pgcatalog.py,sha256=V1NYLEUSXHpWmgcPIo1HS2riK_HDXSi-uykJjSoOOrE,9033
235
+ nucliadb/search/search/pgcatalog.py,sha256=s_J98fsX_RuFXwpejpkGqG-tD9ELuzz4YQ6U3ew5h2g,9313
234
236
  nucliadb/search/search/predict_proxy.py,sha256=IFI3v_ODz2_UU1XZnyaD391fE7-2C0npSmj_HmDvzS4,3123
235
237
  nucliadb/search/search/query.py,sha256=CCz58Cs_VKxbwGO6VdhOzl9HXwKny2hfH2llJVR9emM,29859
236
238
  nucliadb/search/search/rank_fusion.py,sha256=tRGo_KlsFsVx1CQEy1iqQ6f0T1Dq1kf0axDXHuuzvvM,6946
237
239
  nucliadb/search/search/rerankers.py,sha256=3vep4EOVNeDJGsMdx-1g6Ar4ZGJG3IHym3HkxnbwtAQ,7321
238
- nucliadb/search/search/shards.py,sha256=JSRSrHgHcF4sXyuZZoJdMfK0v_LHpoSRf1lCr5-K5ko,2742
240
+ nucliadb/search/search/shards.py,sha256=OEtN1p9WX_cMX8t-myaafpmFAPTpUEOutR7z1sDuNcY,3242
239
241
  nucliadb/search/search/summarize.py,sha256=ksmYPubEQvAQgfPdZHfzB_rR19B2ci4IYZ6jLdHxZo8,4996
240
242
  nucliadb/search/search/utils.py,sha256=iF2tbBA56gRMJH1TlE2hMrqeXqjoeOPt4KgRdp2m9Ek,3313
241
243
  nucliadb/search/search/chat/__init__.py,sha256=cp15ZcFnHvpcu_5-aK2A4uUyvuZVV_MJn4bIXMa20ks,835
@@ -245,13 +247,15 @@ nucliadb/search/search/chat/images.py,sha256=PA8VWxT5_HUGfW1ULhKTK46UBsVyINtWWqE
245
247
  nucliadb/search/search/chat/prompt.py,sha256=Jnja-Ss7skgnnDY8BymVfdeYsFPnIQFL8tEvcRXTKUE,47356
246
248
  nucliadb/search/search/chat/query.py,sha256=0IoeW-JNaRBe2d9C3bXNfkYpzmsN_IIg3U4Vqb8eOEk,16485
247
249
  nucliadb/search/search/query_parser/__init__.py,sha256=cp15ZcFnHvpcu_5-aK2A4uUyvuZVV_MJn4bIXMa20ks,835
248
- nucliadb/search/search/query_parser/catalog.py,sha256=PtH5nb6UTzH8l7Lmdd1RgLVFsn9CN5M5-JkVq9YeR4k,7116
249
250
  nucliadb/search/search/query_parser/exceptions.py,sha256=szAOXUZ27oNY-OSa9t2hQ5HHkQQC0EX1FZz_LluJHJE,1224
250
251
  nucliadb/search/search/query_parser/fetcher.py,sha256=jhr__J0KmAzjdsTTadWQmD9qf6lZvqlKAfZdYjZH_UY,15742
251
252
  nucliadb/search/search/query_parser/filter_expression.py,sha256=rws5vsKTofX2iMUK4yvjmLZFxtcbWbyhIcwen4j0rQg,6578
252
- nucliadb/search/search/query_parser/models.py,sha256=VHDuyJlU2OLZN1usrQX53TZbPmWhzMeVYY0BiYNFzak,2464
253
+ nucliadb/search/search/query_parser/models.py,sha256=7czH-jHskl9axEnZV5XnQY8cyN_fs14Cpivzd5aaSxc,2686
253
254
  nucliadb/search/search/query_parser/old_filters.py,sha256=-zbfN-RsXoj_DRjh3Lfp-wShwFXgkISawzVptVzja-A,9071
254
- nucliadb/search/search/query_parser/parser.py,sha256=9TwkSNna3s-lCQIqBoSJzm6YbXdu8VIHJUan8M4ysfE,4667
255
+ nucliadb/search/search/query_parser/parsers/__init__.py,sha256=ySCNSdbesLXGZyR88919njulA6UE10_3PhqMG_Yj1o4,1034
256
+ nucliadb/search/search/query_parser/parsers/catalog.py,sha256=XdBiTweGTQkj8m_V_i2xbwp7P5pPO8K1Tud692XKhMw,7149
257
+ nucliadb/search/search/query_parser/parsers/find.py,sha256=q3wH_i0DGceeKckYEH3c5MqM5EvRiMCL7r-6nCAId9Q,4666
258
+ nucliadb/search/search/query_parser/parsers/graph.py,sha256=4cR-Y_ZUX-QNYhL6DV2tanmBlSb0ducf4J3hb9VXLh8,6261
255
259
  nucliadb/standalone/__init__.py,sha256=cp15ZcFnHvpcu_5-aK2A4uUyvuZVV_MJn4bIXMa20ks,835
256
260
  nucliadb/standalone/api_router.py,sha256=hgq9FXpihzgjHkwcVGfGCSwyXy67fqXTfLFHuINzIi0,5567
257
261
  nucliadb/standalone/app.py,sha256=mAApNK_iVsQgJyd-mtwCeZq5csSimwnXmlQGH9a70pE,5586
@@ -272,7 +276,7 @@ nucliadb/tasks/consumer.py,sha256=xc0Ql3N1Iq52dJ3t4YYGJFj1NCQAly0J5W_brfLa_F8,68
272
276
  nucliadb/tasks/logger.py,sha256=C7keOEO_mjLVp5VbqAZ2QXfqVB2Hot7NgBlUP_SDSMw,924
273
277
  nucliadb/tasks/models.py,sha256=qrZKi5DNDQ07waMsp5L4_Fi7WRs57YiO-kmXlrBzEAA,1168
274
278
  nucliadb/tasks/producer.py,sha256=UnpJAzhj_GElsCoO5G6T4m6MshsgOaqR2tVzJmEta64,2625
275
- nucliadb/tasks/retries.py,sha256=Zv-3Hys-SKayG9VQ7_7EIflkegE5j-xPGrf-nwaxsfY,5075
279
+ nucliadb/tasks/retries.py,sha256=tLNtwAutGEfFV3Adr4a9ew-Wg4vuxBd72GGDE_Mma8s,5160
276
280
  nucliadb/tasks/utils.py,sha256=tV1AbWdFc3qfIULX44Veqj41FCD1B6XYjG6brULBeiw,1459
277
281
  nucliadb/tests/__init__.py,sha256=cp15ZcFnHvpcu_5-aK2A4uUyvuZVV_MJn4bIXMa20ks,835
278
282
  nucliadb/tests/config.py,sha256=JN_Jhgj-fwM9_8IeO9pwxr6C1PiwRDrXxm67Y38rU30,2080
@@ -347,8 +351,8 @@ nucliadb/writer/tus/local.py,sha256=7jYa_w9b-N90jWgN2sQKkNcomqn6JMVBOVeDOVYJHto,
347
351
  nucliadb/writer/tus/s3.py,sha256=vF0NkFTXiXhXq3bCVXXVV-ED38ECVoUeeYViP8uMqcU,8357
348
352
  nucliadb/writer/tus/storage.py,sha256=ToqwjoYnjI4oIcwzkhha_MPxi-k4Jk3Lt55zRwaC1SM,2903
349
353
  nucliadb/writer/tus/utils.py,sha256=MSdVbRsRSZVdkaum69_0wku7X3p5wlZf4nr6E0GMKbw,2556
350
- nucliadb-6.3.1.post3577.dist-info/METADATA,sha256=7cMll6LH15F3_kAg1yrlOSDK8XFk77amc4TEa0kApug,4291
351
- nucliadb-6.3.1.post3577.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
352
- nucliadb-6.3.1.post3577.dist-info/entry_points.txt,sha256=XqGfgFDuY3zXQc8ewXM2TRVjTModIq851zOsgrmaXx4,1268
353
- nucliadb-6.3.1.post3577.dist-info/top_level.txt,sha256=hwYhTVnX7jkQ9gJCkVrbqEG1M4lT2F_iPQND1fCzF80,20
354
- nucliadb-6.3.1.post3577.dist-info/RECORD,,
354
+ nucliadb-6.3.1.post3590.dist-info/METADATA,sha256=cnyGLiXObJPzQkmY-I7Ilyq2TvPG9l48K1TrnPhqreQ,4291
355
+ nucliadb-6.3.1.post3590.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
356
+ nucliadb-6.3.1.post3590.dist-info/entry_points.txt,sha256=XqGfgFDuY3zXQc8ewXM2TRVjTModIq851zOsgrmaXx4,1268
357
+ nucliadb-6.3.1.post3590.dist-info/top_level.txt,sha256=hwYhTVnX7jkQ9gJCkVrbqEG1M4lT2F_iPQND1fCzF80,20
358
+ nucliadb-6.3.1.post3590.dist-info/RECORD,,