11import abc
2- from typing import overload , Optional , Union , Dict , List , Tuple , Callable , TYPE_CHECKING
2+ from typing import TYPE_CHECKING , Callable , Dict , List , Optional , Tuple , Union , overload
33
44import numpy as np
5-
65from docarray .math import ndarray
76from docarray .score import NamedScore
87
98if TYPE_CHECKING : # pragma: no cover
10- from docarray .typing import T , ArrayType
11-
129 from docarray import Document , DocumentArray
10+ from docarray .typing import ArrayType , T
1311
1412
1513class FindMixin :
@@ -99,6 +97,7 @@ def find(
9997 filter : Union [Dict , str , None ] = None ,
10098 only_id : bool = False ,
10199 index : str = 'text' ,
100+ return_root : Optional [bool ] = False ,
102101 on : Optional [str ] = None ,
103102 ** kwargs ,
104103 ) -> Union ['DocumentArray' , List ['DocumentArray' ]]:
@@ -126,14 +125,17 @@ def find(
126125 parameter is ignored. By default, the Document `text` attribute will be used for search,
127126 otherwise the tag field specified by `index` will be used. You can only use this parameter if the
128127 storage backend supports searching by text.
128+ :param return_root: if set, then the root-level DocumentArray will be returned
129129 :param on: specifies a subindex to search on. If set, the returned DocumentArray will be retrieved from the given subindex.
130130 :param kwargs: other kwargs.
131131
132132 :return: a list of DocumentArrays containing the closest Document objects for each of the queries in `query`.
133133 """
134+ from docarray import Document , DocumentArray
135+
134136 index_da = self ._get_index (subindex_name = on )
135137 if index_da is not self :
136- return index_da .find (
138+ results = index_da .find (
137139 query ,
138140 metric ,
139141 limit ,
@@ -144,7 +146,15 @@ def find(
144146 index ,
145147 on = None ,
146148 )
147- from docarray import Document , DocumentArray
149+
150+ if return_root :
151+ da = self ._get_root_docs (results )
152+ for d , s in zip (da , results [:, 'scores' ]):
153+ d .scores = s
154+
155+ return da
156+
157+ return results
148158
149159 if isinstance (query , dict ):
150160 if filter is None :
@@ -301,3 +311,15 @@ def _find_by_text(self, *args, **kwargs):
301311 raise NotImplementedError (
302312 f'Search by text is not supported with this backend { self .__class__ .__name__ } '
303313 )
314+
315+ def _get_root_docs (self , docs : 'DocumentArray' ) -> 'DocumentArray' :
316+ """Get the root documents of the current DocumentArray.
317+
318+ :return: a `DocumentArray` containing the root documents.
319+ """
320+
321+ if not all (docs [:, 'tags___root_id_' ]):
322+ raise ValueError (
323+ f'Not all Documents in this subindex have the "_root_id_" attribute set in all `tags`.'
324+ )
325+ return self [docs [:, 'tags___root_id_' ]]
0 commit comments