@@ -31,20 +31,11 @@ def _query_rel_to_abs(x_sel, rel_indices, rank):
3131 """Map arrayQuery relative indices (within a sub-array) to absolute dataset indices.
3232
3333 x_sel: SimpleSelection whose sub-array was queried
34- rel_indices: arrayQuery result — (N,) for rank=1, (N, rank) for rank>1
34+ rel_indices: arrayQuery result, ndarray of shape (N, rank)
3535 """
3636 slices = x_sel .slices
37- if rank == 1 :
38- s = slices [0 ]
39- if isinstance (s , slice ):
40- start = s .start if s .start is not None else 0
41- step = s .step if s .step is not None else 1
42- return (rel_indices * step + start ).astype (np .dtype ('u8' ))
43- if isinstance (s , list ):
44- return np .array (s , dtype = 'u8' )[rel_indices .astype (int )]
45- return np .full (len (rel_indices ), int (s ), dtype = 'u8' )
4637 if len (rel_indices ) == 0 :
47- return rel_indices . astype ( 'u8' )
38+ return np . zeros (( 0 , rank ), dtype = 'u8' )
4839 abs_result = np .zeros ((len (rel_indices ), rank ), dtype = 'u8' )
4940 for d in range (rank ):
5041 s = slices [d ]
@@ -696,7 +687,7 @@ def deleteAttribute(self, obj_id, name):
696687
697688 self .make_dirty (obj_id )
698689
699- def getDatasetValues (self , dset_id , sel , query = None ):
690+ def getDatasetValues (self , dset_id , sel ):
700691 """
701692 Get values from dataset identified by obj_id.
702693 If a slices list or tuple is provided, it should have the same
@@ -796,8 +787,6 @@ def init_arr(rdtype, cpl):
796787 raise ValueError ("Only SELECT_ALL selections are supported for scalar datasets" )
797788 if sel .shape != ():
798789 raise ValueError ("Selection shape does not match dataset shape" )
799- if query :
800- raise ValueError ("Query is not supported for scalar datasets" )
801790 if updates :
802791 # for scalars the update has to be the requested value
803792 (update_sel , arr ) = updates [- 1 ]
@@ -816,55 +805,6 @@ def init_arr(rdtype, cpl):
816805 arr = None
817806 fetch = True
818807
819- if query :
820- full_shape = sel .shape
821- rank = len (full_shape )
822- result_mask = np .zeros (full_shape , dtype = bool )
823-
824- # Delegate query to the reader when it has relevant data
825- query_fetch = not (isinstance (self ._reader , H5NullReader ) or dset_id in self ._new_objects )
826- if query_fetch :
827- for (update_sel , _ ) in updates :
828- if selections .contained (sel , update_sel ):
829- query_fetch = False
830- break
831-
832- if query_fetch :
833- reader_result = self .reader .getDatasetValues (dset_id , sel , dtype = dtype , query = query )
834- if reader_result is not None and len (reader_result ) > 0 :
835- if rank == 1 :
836- result_mask [reader_result .astype (int )] = True
837- else :
838- result_mask [tuple (reader_result [:, d ].astype (int ) for d in range (rank ))] = True
839-
840- for (update_sel , update_val ) in updates :
841- x_sel = selections .intersect (sel , update_sel )
842- if x_sel .nselect == 0 :
843- continue
844-
845- # Invalidate reader results overwritten by this update
846- inter_mask = np .zeros (full_shape , dtype = bool )
847- inter_mask [x_sel .slices ] = True
848- result_mask &= ~ inter_mask
849-
850- # Query the updated values at the intersection
851- local_sel = selections .translate (update_sel , x_sel )
852- x_vals = update_val [local_sel .slices ]
853- x_rel = arrayQuery (query , x_vals )
854-
855- if len (x_rel ) > 0 :
856- abs_result = _query_rel_to_abs (x_sel , x_rel , rank )
857- if rank == 1 :
858- result_mask [abs_result .astype (int )] = True
859- else :
860- result_mask [tuple (abs_result [:, d ].astype (int ) for d in range (rank ))] = True
861-
862- indices = np .argwhere (result_mask )
863- if rank == 1 :
864- return indices .reshape (- 1 ).astype (np .dtype ('u8' ))
865- else :
866- return indices .astype (np .dtype ('u8' ))
867-
868808 # determine if we need to get data from the reader
869809 if isinstance (self ._reader , H5NullReader ) or dset_id in self ._new_objects :
870810 fetch = False
@@ -981,6 +921,101 @@ def init_arr(rdtype, cpl):
981921
982922 return arr
983923
924+ def queryDataset (self , dset_id , query , sel = None , limit = 0 ):
925+ """
926+ Query the given dataset using the selection and query expression
927+ If sel is provided, only the elements in the selection will be queried,
928+ otherwise the entire dataset will be queried.
929+ If limit is provided, only the first limit number of elements that match the query will be returned.
930+
931+ Return a numpy array of indices for the elements that match the query
932+ """
933+
934+ def queryReader (dset_id , query , sel = None , limit = 0 ):
935+ result = None
936+ try :
937+ result = self .reader .queryDataset (dset_id , query , sel = sel , limit = limit )
938+ except NotImplementedError :
939+ print ("This reader doesn't support queryDataset" )
940+
941+ if result is not None :
942+ return result
943+
944+ # query the dataset by fetching the data and applying the query locally
945+ arr = self .getDatasetValues (dset_id , sel )
946+
947+ result = arrayQuery (query , arr , limit = limit )
948+ result = _query_rel_to_abs (sel , result , len (sel .shape ))
949+
950+ return result
951+ #
952+ # start of queryDataset
953+ #
954+ if not isinstance (query , str ):
955+ raise TypeError ("Expected query string" )
956+
957+ if sel is not None and not isinstance (sel , selections .Selection ):
958+ raise TypeError ("Expected Selection class" )
959+ if not isinstance (limit , int ) or limit < 0 :
960+ raise TypeError ("Expected non-negative integer for limit" )
961+
962+ dset_json = self .getObjectById (dset_id )
963+ shape_json = dset_json ["shape" ]
964+
965+ shape_class = getShapeClass (shape_json )
966+ if shape_class == "H5S_NULL" :
967+ raise ValueError ("querying null space dataset not supported" )
968+ dims = getShapeDims (shape_json )
969+ if sel is None :
970+ sel = selections .select (dims , ...)
971+
972+ updates = self ._getDatasetUpdates (dset_id )
973+
974+ if sel .shape != dims :
975+ raise TypeError ("Selection shape does not match dataset shape" )
976+
977+ full_shape = sel .shape
978+ rank = len (full_shape )
979+
980+ # Delegate query to the reader when it has relevant data
981+ query_fetch = not (isinstance (self ._reader , H5NullReader ) or dset_id in self ._new_objects )
982+ if query_fetch :
983+ for (update_sel , _ ) in updates :
984+ if selections .contained (sel , update_sel ):
985+ query_fetch = False
986+ break
987+
988+ result_mask = np .zeros (full_shape , dtype = bool )
989+ if query_fetch :
990+ fetched = queryReader (dset_id , query , sel = sel , limit = limit )
991+ if len (fetched ) > 0 :
992+ result_mask [tuple (fetched [:, d ].astype (int ) for d in range (rank ))] = True
993+
994+ for (update_sel , update_val ) in updates :
995+ x_sel = selections .intersect (sel , update_sel )
996+ if x_sel .nselect == 0 :
997+ continue
998+
999+ # Invalidate reader results overwritten by this update
1000+ inter_mask = np .zeros (full_shape , dtype = bool )
1001+ inter_mask [x_sel .slices ] = True
1002+ result_mask &= ~ inter_mask
1003+
1004+ # Query the updated values at the intersection
1005+ local_sel = selections .translate (update_sel , x_sel )
1006+ x_vals = update_val [local_sel .slices ]
1007+ x_rel = arrayQuery (query , x_vals )
1008+
1009+ if len (x_rel ) > 0 :
1010+ abs_result = _query_rel_to_abs (x_sel , x_rel , rank )
1011+ result_mask [tuple (abs_result [:, d ].astype (int ) for d in range (rank ))] = True
1012+
1013+ indices = np .argwhere (result_mask )
1014+ if limit > 0 and len (indices ) > limit :
1015+ indices = indices [:limit ]
1016+
1017+ return indices
1018+
9841019 def setDatasetValues (self , dset_id , sel , arr ):
9851020 """
9861021 Write the given ndarray to the dataset using the selection
0 commit comments