@@ -201,18 +201,71 @@ Iterable<Node<N>> scanLayer(@Nonnull ReadTransaction readTransaction, int layer,
201201 int maxNumRead );
202202
203203 /**
204- * Fetches the entry node reference for the HNSW index .
204+ * Creates a {@code HalfRealVector} from a given {@code Tuple} .
205205 * <p>
206- * This method performs an asynchronous read to retrieve the stored entry point of the index. The entry point
207- * information, which includes its primary key, vector, and the layer value, is packed into a single key-value
208- * pair within a dedicated subspace. If no entry node is found, it indicates that the index is empty .
206+ * This method assumes the vector data is stored as a byte array at the first. position (index 0) of the tuple. It
207+ * extracts this byte array and then delegates to the {@link #vectorFromBytes(HNSW.Config, byte[])} method for the
208+ * actual conversion .
209209 * @param config an HNSW configuration
210- * @param readTransaction the transaction to use for the read operation
211- * @param subspace the subspace where the HNSW index data is stored
212- * @param onReadListener a listener to be notified of the key-value read operation
213- * @return a {@link CompletableFuture} that will complete with the {@link AccessInfo}
214- * for the index's entry point, or with {@code null} if the index is empty
210+ * @param vectorTuple the tuple containing the vector data as a byte array at index 0. Must not be {@code null}.
211+ * @return a new {@code HalfRealVector} instance created from the tuple's data.
212+ * This method never returns {@code null}.
215213 */
214+ @ Nonnull
215+ static RealVector vectorFromTuple (@ Nonnull final HNSW .Config config , @ Nonnull final Tuple vectorTuple ) {
216+ return vectorFromBytes (config , vectorTuple .getBytes (0 ));
217+ }
218+
219+ /**
220+ * Creates a {@link RealVector} from a byte array.
221+ * <p>
222+ * This method interprets the input byte array by interpreting the first byte of the array as the precision shift.
223+ * The byte array must have the proper size, i.e. the invariant {@code (bytesLength - 1) % precision == 0} must
224+ * hold.
225+ * @param config an HNSW config
226+ * @param vectorBytes the non-null byte array to convert.
227+ * @return a new {@link RealVector} instance created from the byte array.
228+ * @throws com.google.common.base.VerifyException if the length of {@code vectorBytes} does not meet the invariant
229+ * {@code (bytesLength - 1) % precision == 0}
230+ */
231+ @ Nonnull
232+ static RealVector vectorFromBytes (@ Nonnull final HNSW .Config config , @ Nonnull final byte [] vectorBytes ) {
233+ final byte vectorTypeOrdinal = vectorBytes [0 ];
234+ switch (fromVectorTypeOrdinal (vectorTypeOrdinal )) {
235+ case HALF :
236+ return HalfRealVector .fromBytes (vectorBytes );
237+ case SINGLE :
238+ return FloatRealVector .fromBytes (vectorBytes );
239+ case DOUBLE :
240+ return DoubleRealVector .fromBytes (vectorBytes );
241+ case RABITQ :
242+ Verify .verify (config .isUseRaBitQ ());
243+ return EncodedRealVector .fromBytes (vectorBytes , config .getNumDimensions (),
244+ config .getRaBitQNumExBits ());
245+ default :
246+ throw new RuntimeException ("unable to serialize vector" );
247+ }
248+ }
249+
250+ /**
251+ * Converts a {@link RealVector} into a {@link Tuple}.
252+ * <p>
253+ * This method first serializes the given vector into a byte array using the {@link RealVector#getRawData()} getter
254+ * method. It then creates a {@link Tuple} from the resulting byte array.
255+ * @param vector the vector of {@code Half} precision floating-point numbers to convert. Cannot be null.
256+ * @return a new, non-null {@code Tuple} instance representing the contents of the vector.
257+ */
258+ @ Nonnull
259+ @ SuppressWarnings ("PrimitiveArrayArgumentToVarargsMethod" )
260+ static Tuple tupleFromVector (final RealVector vector ) {
261+ return Tuple .from (vector .getRawData ());
262+ }
263+
264+ @ Nonnull
265+ static VectorType fromVectorTypeOrdinal (final int ordinal ) {
266+ return VECTOR_TYPES .get (ordinal );
267+ }
268+
216269 @ Nonnull
217270 static CompletableFuture <AccessInfo > fetchAccessInfo (@ Nonnull final HNSW .Config config ,
218271 @ Nonnull final ReadTransaction readTransaction ,
@@ -274,15 +327,14 @@ static void writeAccessInfo(@Nonnull final Transaction transaction,
274327 }
275328
276329 @ Nonnull
277- static CompletableFuture <List <AggregatedVector >> readSampledVectors (@ Nonnull final ReadTransaction readTransaction ,
278- @ Nonnull final Subspace subspace ,
279- final int numMaxVectors ,
280- @ Nonnull final OnReadListener onReadListener ) {
281- final Subspace prefixSubspace =
282- subspace .subspace (Tuple .from (SUBSPACE_PREFIX_SAMPLES ));
330+ static CompletableFuture <List <AggregatedVector >> consumeSampledVectors (@ Nonnull final Transaction transaction ,
331+ @ Nonnull final Subspace subspace ,
332+ final int numMaxVectors ,
333+ @ Nonnull final OnReadListener onReadListener ) {
334+ final Subspace prefixSubspace = subspace .subspace (Tuple .from (SUBSPACE_PREFIX_SAMPLES ));
283335
284336 final byte [] prefixKey = prefixSubspace .pack ();
285- final ReadTransaction snapshot = readTransaction .snapshot ();
337+ final ReadTransaction snapshot = transaction .snapshot ();
286338 final Range range = Range .startsWith (prefixKey );
287339
288340 return AsyncUtil .collect (snapshot .getRange (range , numMaxVectors , true , StreamingMode .ITERATOR ),
@@ -293,39 +345,27 @@ static CompletableFuture<List<AggregatedVector>> readSampledVectors(@Nonnull fin
293345 final byte [] key = keyValue .getKey ();
294346 final byte [] value = keyValue .getValue ();
295347 resultBuilder .add (aggregatedVectorFromRaw (prefixSubspace , key , value ));
296- readTransaction . addReadConflictKeyIfNotSnapshot (key );
348+ transaction . clear (key );
297349 onReadListener .onKeyValueRead (-1 , key , value );
298350 }
299351 return resultBuilder .build ();
300352 });
301353 }
302354
303- private static AggregatedVector aggregatedVectorFromRaw (@ Nonnull final Subspace prefixSubspace ,
304- @ Nonnull final byte [] key ,
305- @ Nonnull final byte [] value ) {
306- final Tuple keyTuple = prefixSubspace .unpack (key );
307- final int partialCount = Math .toIntExact (keyTuple .getLong (0 ));
308- final RealVector vector = DoubleRealVector .fromBytes (Tuple .fromBytes (value ).getBytes (0 ));
309-
310- return new AggregatedVector (partialCount , vector );
311- }
312-
313355 static void appendSampledVector (@ Nonnull final Transaction transaction ,
314356 @ Nonnull final Subspace subspace ,
315357 final int partialCount ,
316358 @ Nonnull final RealVector vector ,
317359 @ Nonnull final OnWriteListener onWriteListener ) {
318- final Subspace prefixSubspace =
319- subspace .subspace (Tuple .from (SUBSPACE_PREFIX_SAMPLES ));
360+ final Subspace prefixSubspace = subspace .subspace (Tuple .from (SUBSPACE_PREFIX_SAMPLES ));
320361 final Subspace keySubspace = prefixSubspace .subspace (Tuple .from (partialCount , UUID .randomUUID ()));
321362 final byte [] prefixKey = keySubspace .pack ();
322363 final byte [] value = tupleFromVector (vector .toDoubleRealVector ()).pack ();
323364 transaction .set (prefixKey , value );
324365 onWriteListener .onKeyValueWritten (-1 , prefixKey , value );
325366 }
326367
327- static void removeAllSampledVectors (@ Nonnull final Transaction transaction ,
328- @ Nonnull final Subspace subspace ) {
368+ static void removeAllSampledVectors (@ Nonnull final Transaction transaction , @ Nonnull final Subspace subspace ) {
329369 final Subspace prefixSubspace =
330370 subspace .subspace (Tuple .from (SUBSPACE_PREFIX_SAMPLES ));
331371
@@ -334,69 +374,14 @@ static void removeAllSampledVectors(@Nonnull final Transaction transaction,
334374 transaction .clear (range );
335375 }
336376
337- /**
338- * Creates a {@code HalfRealVector} from a given {@code Tuple}.
339- * <p>
340- * This method assumes the vector data is stored as a byte array at the first. position (index 0) of the tuple. It
341- * extracts this byte array and then delegates to the {@link #vectorFromBytes(HNSW.Config, byte[])} method for the
342- * actual conversion.
343- * @param config an HNSW configuration
344- * @param vectorTuple the tuple containing the vector data as a byte array at index 0. Must not be {@code null}.
345- * @return a new {@code HalfRealVector} instance created from the tuple's data.
346- * This method never returns {@code null}.
347- */
348377 @ Nonnull
349- static RealVector vectorFromTuple (@ Nonnull final HNSW .Config config , @ Nonnull final Tuple vectorTuple ) {
350- return vectorFromBytes (config , vectorTuple .getBytes (0 ));
351- }
352-
353- /**
354- * Creates a {@link RealVector} from a byte array.
355- * <p>
356- * This method interprets the input byte array by interpreting the first byte of the array as the precision shift.
357- * The byte array must have the proper size, i.e. the invariant {@code (bytesLength - 1) % precision == 0} must
358- * hold.
359- * @param config an HNSW config
360- * @param vectorBytes the non-null byte array to convert.
361- * @return a new {@link RealVector} instance created from the byte array.
362- * @throws com.google.common.base.VerifyException if the length of {@code vectorBytes} does not meet the invariant
363- * {@code (bytesLength - 1) % precision == 0}
364- */
365- @ Nonnull
366- static RealVector vectorFromBytes (@ Nonnull final HNSW .Config config , @ Nonnull final byte [] vectorBytes ) {
367- final byte vectorTypeOrdinal = vectorBytes [0 ];
368- switch (fromVectorTypeOrdinal (vectorTypeOrdinal )) {
369- case HALF :
370- return HalfRealVector .fromBytes (vectorBytes );
371- case SINGLE :
372- return FloatRealVector .fromBytes (vectorBytes );
373- case DOUBLE :
374- return DoubleRealVector .fromBytes (vectorBytes );
375- case RABITQ :
376- Verify .verify (config .isUseRaBitQ ());
377- return EncodedRealVector .fromBytes (vectorBytes , config .getNumDimensions (),
378- config .getRaBitQNumExBits ());
379- default :
380- throw new RuntimeException ("unable to serialize vector" );
381- }
382- }
383-
384- /**
385- * Converts a {@link RealVector} into a {@link Tuple}.
386- * <p>
387- * This method first serializes the given vector into a byte array using the {@link RealVector#getRawData()} getter
388- * method. It then creates a {@link Tuple} from the resulting byte array.
389- * @param vector the vector of {@code Half} precision floating-point numbers to convert. Cannot be null.
390- * @return a new, non-null {@code Tuple} instance representing the contents of the vector.
391- */
392- @ Nonnull
393- @ SuppressWarnings ("PrimitiveArrayArgumentToVarargsMethod" )
394- static Tuple tupleFromVector (final RealVector vector ) {
395- return Tuple .from (vector .getRawData ());
396- }
378+ private static AggregatedVector aggregatedVectorFromRaw (@ Nonnull final Subspace prefixSubspace ,
379+ @ Nonnull final byte [] key ,
380+ @ Nonnull final byte [] value ) {
381+ final Tuple keyTuple = prefixSubspace .unpack (key );
382+ final int partialCount = Math .toIntExact (keyTuple .getLong (0 ));
383+ final RealVector vector = DoubleRealVector .fromBytes (Tuple .fromBytes (value ).getBytes (0 ));
397384
398- @ Nonnull
399- static VectorType fromVectorTypeOrdinal (final int ordinal ) {
400- return VECTOR_TYPES .get (ordinal );
385+ return new AggregatedVector (partialCount , vector );
401386 }
402387}
0 commit comments