github.com/weaviate/weaviate@v1.24.6/adapters/repos/db/vector/hnsw/compress_sift_test.go (about)

     1  //                           _       _
     2  // __      _____  __ ___   ___  __ _| |_ ___
     3  // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
     4  //  \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
     5  //   \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
     6  //
     7  //  Copyright © 2016 - 2024 Weaviate B.V. All rights reserved.
     8  //
     9  //  CONTACT: hello@weaviate.io
    10  //
    11  
    12  //go:build benchmarkSiftRecall
    13  // +build benchmarkSiftRecall
    14  
    15  package hnsw_test
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"io/ioutil"
    21  	"math"
    22  	"os"
    23  	"strconv"
    24  	"strings"
    25  	"sync"
    26  	"testing"
    27  	"time"
    28  
    29  	"github.com/sirupsen/logrus/hooks/test"
    30  	"github.com/stretchr/testify/assert"
    31  	"github.com/stretchr/testify/require"
    32  	"github.com/weaviate/weaviate/adapters/repos/db/lsmkv"
    33  	"github.com/weaviate/weaviate/adapters/repos/db/vector/compressionhelpers"
    34  	"github.com/weaviate/weaviate/adapters/repos/db/vector/hnsw"
    35  	"github.com/weaviate/weaviate/adapters/repos/db/vector/hnsw/distancer"
    36  	"github.com/weaviate/weaviate/adapters/repos/db/vector/testinghelpers"
    37  	"github.com/weaviate/weaviate/entities/cyclemanager"
    38  	ent "github.com/weaviate/weaviate/entities/vectorindex/hnsw"
    39  )
    40  
    41  func distanceWrapper(provider distancer.Provider) func(x, y []float32) float32 {
    42  	return func(x, y []float32) float32 {
    43  		dist, _, _ := provider.SingleDist(x, y)
    44  		return dist
    45  	}
    46  }
    47  
    48  const rootPath = "doesnt-matter-as-committlogger-is-mocked-out"
    49  
    50  func TestRecall(t *testing.T) {
    51  	defer func(path string) {
    52  		err := os.RemoveAll(path)
    53  		if err != nil {
    54  			fmt.Println(err)
    55  		}
    56  	}(rootPath)
    57  	fmt.Println("Sift1MPQKMeans 10K/1K")
    58  	efConstruction := 64
    59  	ef := 32
    60  	maxNeighbors := 32
    61  	dimensions := 128
    62  	vectors_size := 200000
    63  	queries_size := 100
    64  	switch_at := vectors_size
    65  	before := time.Now()
    66  	vectors, queries := testinghelpers.RandomVecs(vectors_size, queries_size, dimensions)
    67  	k := 10
    68  	distancer := distancer.NewL2SquaredProvider()
    69  	fmt.Printf("generating data took %s\n", time.Since(before))
    70  
    71  	uc := ent.UserConfig{}
    72  	uc.MaxConnections = maxNeighbors
    73  	uc.EFConstruction = efConstruction
    74  	uc.EF = ef
    75  	uc.VectorCacheMaxObjects = 10e12
    76  
    77  	index, _ := hnsw.New(hnsw.Config{
    78  		RootPath:              rootPath,
    79  		ID:                    "recallbenchmark",
    80  		MakeCommitLoggerThunk: hnsw.MakeNoopCommitLogger,
    81  		DistanceProvider:      distancer,
    82  		VectorForIDThunk: func(ctx context.Context, id uint64) ([]float32, error) {
    83  			return vectors[int(id)], nil
    84  		},
    85  	}, uc, newDummyStore(t))
    86  	init := time.Now()
    87  	compressionhelpers.Concurrently(uint64(switch_at), func(_, id uint64, _ *sync.Mutex) {
    88  		index.Add(uint64(id), vectors[id])
    89  		if id%1000 == 0 {
    90  			fmt.Println(id, time.Since(before))
    91  		}
    92  	})
    93  	before = time.Now()
    94  	uc.PQ.Enabled = true
    95  	index.UpdateUserConfig(uc, func() {}) /*should have configuration.pr.enabled = true*/
    96  	fmt.Printf("Time to compress: %s", time.Since(before))
    97  	fmt.Println()
    98  	compressionhelpers.Concurrently(uint64(vectors_size-switch_at), func(_, id uint64, _ *sync.Mutex) {
    99  		idx := switch_at + int(id)
   100  		index.Add(uint64(idx), vectors[idx])
   101  		if id%1000 == 0 {
   102  			fmt.Println(idx, time.Since(before))
   103  		}
   104  	})
   105  	fmt.Printf("Building the index took %s\n", time.Since(init))
   106  
   107  	lastRecall := float32(0.0)
   108  	for _, currentEF := range []int{32, 64, 128, 256, 512} {
   109  		uc.EF = currentEF
   110  		index.UpdateUserConfig(uc, func() {})
   111  		fmt.Println(currentEF)
   112  		var relevant uint64
   113  		var retrieved int
   114  
   115  		var querying time.Duration = 0
   116  		for i := 0; i < len(queries); i++ {
   117  			truth := testinghelpers.BruteForce(vectors, queries[i], k, distanceWrapper(distancer))
   118  			before = time.Now()
   119  			results, _, _ := index.SearchByVector(queries[i], k, nil)
   120  			querying += time.Since(before)
   121  			retrieved += k
   122  			relevant += testinghelpers.MatchesInLists(truth, results)
   123  		}
   124  
   125  		recall := float32(relevant) / float32(retrieved)
   126  		assert.True(t, recall > float32(lastRecall))
   127  		lastRecall = recall
   128  	}
   129  	assert.True(t, lastRecall > 0.95)
   130  }
   131  
   132  func TestHnswPqGist(t *testing.T) {
   133  	defer func(path string) {
   134  		err := os.RemoveAll(path)
   135  		if err != nil {
   136  			fmt.Println(err)
   137  		}
   138  	}(rootPath)
   139  	params := [][]int{
   140  		//{64, 64, 32},
   141  		{128, 128, 64},
   142  		{256, 256, 128},
   143  		{512, 512, 256},
   144  	}
   145  	dimensions := 960
   146  	vectors_size := 1000000
   147  	queries_size := 1000
   148  	switch_at := 200000
   149  
   150  	before := time.Now()
   151  	vectors, queries := testinghelpers.ReadVecs(vectors_size, queries_size, dimensions, "gist", "../diskAnn/testdata")
   152  	testinghelpers.Normalize(vectors)
   153  	testinghelpers.Normalize(queries)
   154  	for i, v := range vectors {
   155  		for j, x := range v {
   156  			if math.IsNaN(float64(x)) {
   157  				fmt.Println(i, j, v, x)
   158  			}
   159  		}
   160  	}
   161  	k := 100
   162  	distancer := distancer.NewCosineDistanceProvider()
   163  	truths := testinghelpers.BuildTruths(queries_size, vectors_size, queries, vectors, k, distanceWrapper(distancer), "../diskAnn/testdata/gist/cosine")
   164  	fmt.Printf("generating data took %s\n", time.Since(before))
   165  	for segmentRate := 3; segmentRate < 4; segmentRate++ {
   166  		fmt.Println(segmentRate)
   167  		fmt.Println()
   168  		for i := 0; i < len(params); i++ {
   169  			efConstruction := params[i][0]
   170  			ef := params[i][1]
   171  			maxNeighbors := params[i][2]
   172  
   173  			uc := ent.UserConfig{
   174  				MaxConnections:        maxNeighbors,
   175  				EFConstruction:        efConstruction,
   176  				EF:                    ef,
   177  				VectorCacheMaxObjects: 10e12,
   178  				PQ: ent.PQConfig{
   179  					Enabled:  false,
   180  					Segments: dimensions / int(math.Pow(2, float64(segmentRate))),
   181  					Encoder: ent.PQEncoder{
   182  						Type:         ent.PQEncoderTypeKMeans,
   183  						Distribution: ent.PQEncoderDistributionLogNormal,
   184  					},
   185  				},
   186  			}
   187  			index, _ := hnsw.New(hnsw.Config{
   188  				RootPath:              rootPath,
   189  				ID:                    "recallbenchmark",
   190  				MakeCommitLoggerThunk: hnsw.MakeNoopCommitLogger,
   191  				DistanceProvider:      distancer,
   192  				VectorForIDThunk: func(ctx context.Context, id uint64) ([]float32, error) {
   193  					return vectors[int(id)], nil
   194  				},
   195  			}, uc, newDummyStore(t))
   196  			init := time.Now()
   197  			total := 200000
   198  			compressionhelpers.Concurrently(uint64(switch_at), func(_, id uint64, _ *sync.Mutex) {
   199  				total++
   200  				if total%100000 == 0 {
   201  					fmt.Println(total)
   202  				}
   203  				index.Add(uint64(id), vectors[id])
   204  			})
   205  			before = time.Now()
   206  			uc.PQ.Enabled = true
   207  			index.UpdateUserConfig(uc, func() {})
   208  			fmt.Printf("Time to compress: %s", time.Since(before))
   209  			fmt.Println()
   210  			compressionhelpers.Concurrently(uint64(vectors_size-switch_at), func(_, id uint64, _ *sync.Mutex) {
   211  				idx := switch_at + int(id)
   212  				index.Add(uint64(idx), vectors[idx])
   213  			})
   214  			fmt.Printf("Building the index took %s\n", time.Since(init))
   215  			var relevant uint64
   216  			var retrieved int
   217  
   218  			var querying time.Duration = 0
   219  			compressionhelpers.Concurrently(uint64(len(queries)), func(_, i uint64, _ *sync.Mutex) {
   220  				before = time.Now()
   221  				results, _, _ := index.SearchByVector(queries[i], k, nil)
   222  				querying += time.Since(before)
   223  				retrieved += k
   224  				relevant += testinghelpers.MatchesInLists(truths[i], results)
   225  			})
   226  
   227  			recall := float32(relevant) / float32(retrieved)
   228  			latency := float32(querying.Microseconds()) / float32(queries_size)
   229  			fmt.Println(recall, latency)
   230  			assert.True(t, recall > 0.9)
   231  			assert.True(t, latency < 100000)
   232  		}
   233  	}
   234  }
   235  
   236  /*
   237  10K
   238  128 segments, 16 centroids -> 5.280255291s 0.90662 387.505
   239  64 segments, 256 centroids -> 6.585159916s 0.9326827 410.413
   240  
   241  100K
   242  128 segments, 16 centroids -> 1m17.634662125s 0.88258 692.081
   243  64 segments, 256 centroids -> 1m29.259369458s 0.92157 575.844
   244  
   245  100000
   246  128
   247  Building the index took 47.7846745s
   248  0.92627 664.66
   249  
   250  {64, 64, 32, 256, 0},
   251  
   252  	{64, 64, 32, 1024, 1},
   253  	{64, 64, 32, 4096, 1},
   254  	{64, 64, 32, 16384, 1},
   255  	{64, 64, 32, 65536, 1},
   256  
   257  generating data took 2.072473792s
   258  0
   259  Time to compress: 5m39.750884042s
   260  Building the index took 16m30.632114542s
   261  0.91401 747.82
   262  1
   263  Time to compress: 13m12.011102334s
   264  Building the index took 28m12.879802125s
   265  0.89564 1041.358
   266  2
   267  Time to compress: 58m15.252058416s
   268  Building the index took 1h37m10.217039334s
   269  0.90836 2299.629
   270  3
   271  Time to compress: 3h59m39.032524584s
   272  Building the index took 5h54m55.046038916s
   273  0.91295 4786.8
   274  
   275  generating data took 2.119674416s
   276  0
   277  Start compressing...
   278  Time to compress: 1m3.037853584s
   279  Building the index took 3m53.429316209s
   280  0.40992 169.937
   281  1
   282  Start compressing...
   283  Time to compress: 2m4.653952334s
   284  Building the index took 5m44.454856667s
   285  0.46251252 207.299
   286  2
   287  Start compressing...
   288  Time to compress: 4m7.585857584s
   289  Building the index took 8m36.2004675s
   290  0.50494 293.362
   291  3
   292  Start compressing...
   293  Time to compress: 8m16.4155035s
   294  Building the index took 14m37.089003166s
   295  0.54421 390.49
   296  4
   297  Start compressing...
   298  Time to compress: 16m32.313318708s
   299  Building the index took 26m46.66661125s
   300  0.57827 442.589
   301  */
   302  func TestHnswPqSift(t *testing.T) {
   303  	defer func(path string) {
   304  		err := os.RemoveAll(path)
   305  		if err != nil {
   306  			fmt.Println(err)
   307  		}
   308  	}(rootPath)
   309  	params := [][]int{
   310  		{64, 64, 32, 256, 3},
   311  		{64, 64, 32, 512, 3},
   312  		{64, 64, 32, 1024, 3},
   313  		{64, 64, 32, 2048, 3},
   314  		{64, 64, 32, 4096, 3},
   315  		{64, 64, 32, 65536, 3},
   316  	}
   317  	dimensions := 128
   318  	vectors_size := 1000000
   319  	queries_size := 1000
   320  	switch_at := 200000
   321  	fmt.Println("Sift1M PQ")
   322  	before := time.Now()
   323  	vectors, queries := testinghelpers.ReadVecs(vectors_size, queries_size, dimensions, "sift", "../diskAnn/testdata")
   324  	k := 100
   325  	distancer := distancer.NewL2SquaredProvider()
   326  	truths := testinghelpers.BuildTruths(queries_size, vectors_size, queries, vectors, k, distanceWrapper(distancer), "../diskAnn/testdata")
   327  	fmt.Printf("generating data took %s\n", time.Since(before))
   328  	for i := 0; i < len(params); i++ {
   329  		fmt.Println(i)
   330  		efConstruction := params[i][0]
   331  		ef := params[i][1]
   332  		maxNeighbors := params[i][2]
   333  		centroids := params[i][3]
   334  		segmentRate := params[i][4]
   335  		if centroids > switch_at {
   336  			fmt.Println("Increasing switch at...")
   337  			switch_at = 650000
   338  		}
   339  
   340  		uc := ent.UserConfig{
   341  			MaxConnections: maxNeighbors,
   342  			EFConstruction: efConstruction,
   343  			EF:             ef,
   344  			PQ: ent.PQConfig{
   345  				Enabled:  false,
   346  				Segments: dimensions / int(math.Pow(2, float64(segmentRate))),
   347  				Encoder: ent.PQEncoder{
   348  					Type:         ent.PQEncoderTypeTile,
   349  					Distribution: ent.PQEncoderDistributionLogNormal,
   350  				},
   351  			},
   352  			VectorCacheMaxObjects: 10e12,
   353  		}
   354  		index, _ := hnsw.New(hnsw.Config{
   355  			RootPath:              rootPath,
   356  			ID:                    "recallbenchmark",
   357  			MakeCommitLoggerThunk: hnsw.MakeNoopCommitLogger,
   358  			DistanceProvider:      distancer,
   359  			VectorForIDThunk: func(ctx context.Context, id uint64) ([]float32, error) {
   360  				return vectors[int(id)], nil
   361  			},
   362  		}, uc, newDummyStore(t))
   363  		init := time.Now()
   364  		compressionhelpers.Concurrently(uint64(switch_at), func(_, id uint64, _ *sync.Mutex) {
   365  			index.Add(uint64(id), vectors[id])
   366  		})
   367  		before = time.Now()
   368  		fmt.Println("Start compressing...")
   369  
   370  		cfg := ent.PQConfig{
   371  			Enabled:        true,
   372  			Segments:       dimensions / int(math.Pow(2, float64(segmentRate))),
   373  			Centroids:      centroids,
   374  			BitCompression: false,
   375  			Encoder: ent.PQEncoder{
   376  				Type:         ent.PQEncoderTypeKMeans,
   377  				Distribution: ent.PQEncoderDistributionLogNormal,
   378  			},
   379  		}
   380  
   381  		index.Compress(cfg) /*should have configuration.compressed = true*/
   382  		fmt.Printf("Time to compress: %s", time.Since(before))
   383  		fmt.Println()
   384  		compressionhelpers.Concurrently(uint64(vectors_size-switch_at), func(_, id uint64, _ *sync.Mutex) {
   385  			idx := switch_at + int(id)
   386  
   387  			index.Add(uint64(idx), vectors[idx])
   388  		})
   389  		fmt.Printf("Building the index took %s\n", time.Since(init))
   390  
   391  		var relevant uint64
   392  		var retrieved int
   393  
   394  		var querying time.Duration = 0
   395  		compressionhelpers.Concurrently(uint64(len(queries)), func(_, i uint64, _ *sync.Mutex) {
   396  			before = time.Now()
   397  			results, _, _ := index.SearchByVector(queries[i], k, nil)
   398  			querying += time.Since(before)
   399  			retrieved += k
   400  			relevant += testinghelpers.MatchesInLists(truths[i], results)
   401  		})
   402  
   403  		recall := float32(relevant) / float32(retrieved)
   404  		latency := float32(querying.Microseconds()) / float32(queries_size)
   405  		fmt.Println(recall, latency)
   406  		assert.True(t, recall > 0.9)
   407  		assert.True(t, latency < 100000)
   408  	}
   409  }
   410  
   411  func TestHnswPqSiftDeletes(t *testing.T) {
   412  	defer func(path string) {
   413  		err := os.RemoveAll(path)
   414  		if err != nil {
   415  			fmt.Println(err)
   416  		}
   417  	}(rootPath)
   418  	params := [][]int{
   419  		{64, 64, 32},
   420  	}
   421  	dimensions := 128
   422  	vectors_size := 10000
   423  	queries_size := 1000
   424  	switch_at := 2000
   425  	fmt.Println("Sift1M PQ Deletes")
   426  	before := time.Now()
   427  	vectors, queries := testinghelpers.ReadVecs(vectors_size, queries_size, dimensions, "sift", "../diskAnn/testdata")
   428  	k := 100
   429  	distancer := distancer.NewL2SquaredProvider()
   430  	truths := testinghelpers.BuildTruths(queries_size, vectors_size, queries, vectors, k, distanceWrapper(distancer), "../diskAnn/testdata")
   431  	fmt.Printf("generating data took %s\n", time.Since(before))
   432  	for segmentRate := 0; segmentRate < 1; segmentRate++ {
   433  		fmt.Println(segmentRate)
   434  		fmt.Println()
   435  		for i := 0; i < len(params); i++ {
   436  			efConstruction := params[i][0]
   437  			ef := params[i][1]
   438  			maxNeighbors := params[i][2]
   439  
   440  			uc := ent.UserConfig{
   441  				MaxConnections: maxNeighbors,
   442  				EFConstruction: efConstruction,
   443  				EF:             ef,
   444  				PQ: ent.PQConfig{
   445  					Enabled:  false,
   446  					Segments: dimensions / int(math.Pow(2, float64(segmentRate))),
   447  					Encoder: ent.PQEncoder{
   448  						Type:         "tile",
   449  						Distribution: "log-normal",
   450  					},
   451  				},
   452  				VectorCacheMaxObjects: 10e12,
   453  			}
   454  			index, _ := hnsw.New(hnsw.Config{
   455  				RootPath:              rootPath,
   456  				ID:                    "recallbenchmark",
   457  				MakeCommitLoggerThunk: hnsw.MakeNoopCommitLogger,
   458  				DistanceProvider:      distancer,
   459  				VectorForIDThunk: func(ctx context.Context, id uint64) ([]float32, error) {
   460  					return vectors[int(id)], nil
   461  				},
   462  			}, uc, newDummyStore(t))
   463  			init := time.Now()
   464  			compressionhelpers.Concurrently(uint64(switch_at), func(_, id uint64, _ *sync.Mutex) {
   465  				index.Add(uint64(id), vectors[id])
   466  			})
   467  			before = time.Now()
   468  			uc.PQ.Enabled = true
   469  			index.UpdateUserConfig(uc, func() {}) /*should have configuration.compressed = true*/
   470  			fmt.Printf("Time to compress: %s", time.Since(before))
   471  			fmt.Println()
   472  			compressionhelpers.Concurrently(uint64(vectors_size-switch_at), func(_, id uint64, _ *sync.Mutex) {
   473  				idx := switch_at + int(id)
   474  				index.Add(uint64(idx), vectors[idx])
   475  			})
   476  			fmt.Printf("Building the index took %s\n", time.Since(init))
   477  			var relevant uint64
   478  			var retrieved int
   479  
   480  			var querying time.Duration = 0
   481  			compressionhelpers.Concurrently(uint64(len(queries)), func(_, i uint64, _ *sync.Mutex) {
   482  				before = time.Now()
   483  				results, _, _ := index.SearchByVector(queries[i], k, nil)
   484  				querying += time.Since(before)
   485  				retrieved += k
   486  				relevant += testinghelpers.MatchesInLists(truths[i], results)
   487  			})
   488  
   489  			recall := float32(relevant) / float32(retrieved)
   490  			latency := float32(querying.Microseconds()) / float32(queries_size)
   491  			fmt.Println(recall, latency)
   492  			assert.True(t, recall > 0.9)
   493  			assert.True(t, latency < 100000)
   494  		}
   495  	}
   496  }
   497  
   498  func TestHnswPqDeepImage(t *testing.T) {
   499  	defer func(path string) {
   500  		err := os.RemoveAll(path)
   501  		if err != nil {
   502  			fmt.Println(err)
   503  		}
   504  	}(rootPath)
   505  	vectors_size := 9990000
   506  	queries_size := 1000
   507  	vectors := parseFromTxt("../diskAnn/testdata/deep-image/train.txt", vectors_size)
   508  	queries := parseFromTxt("../diskAnn/testdata/deep-image/test.txt", queries_size)
   509  	dimensions := 96
   510  
   511  	params := [][]int{
   512  		{64, 64, 32},
   513  		{128, 128, 64},
   514  		{256, 256, 128},
   515  		{512, 512, 256},
   516  	}
   517  	switch_at := 1000000
   518  
   519  	fmt.Println("Sift1MPQKMeans 10K/10K")
   520  	before := time.Now()
   521  	k := 100
   522  	distancer := distancer.NewL2SquaredProvider()
   523  	truths := testinghelpers.BuildTruths(queries_size, vectors_size, queries, vectors, k, distanceWrapper(distancer), "../diskAnn/testdata/deep-image")
   524  	fmt.Printf("generating data took %s\n", time.Since(before))
   525  	for segmentRate := 1; segmentRate < 4; segmentRate++ {
   526  		fmt.Println(segmentRate)
   527  		fmt.Println()
   528  		for i := 0; i < len(params); i++ {
   529  			efConstruction := params[i][0]
   530  			ef := params[i][1]
   531  			maxNeighbors := params[i][2]
   532  
   533  			uc := ent.UserConfig{
   534  				MaxConnections: maxNeighbors,
   535  				EFConstruction: efConstruction,
   536  				EF:             ef,
   537  				PQ: ent.PQConfig{
   538  					Enabled:  false,
   539  					Segments: dimensions / int(math.Pow(2, float64(segmentRate))),
   540  					Encoder: ent.PQEncoder{
   541  						Type:         ent.PQEncoderTypeKMeans,
   542  						Distribution: ent.PQEncoderDistributionNormal,
   543  					},
   544  				},
   545  				VectorCacheMaxObjects: 10e12,
   546  			}
   547  			index, _ := hnsw.New(hnsw.Config{
   548  				RootPath:              rootPath,
   549  				ID:                    "recallbenchmark",
   550  				MakeCommitLoggerThunk: hnsw.MakeNoopCommitLogger,
   551  				DistanceProvider:      distancer,
   552  				VectorForIDThunk: func(ctx context.Context, id uint64) ([]float32, error) {
   553  					return vectors[int(id)], nil
   554  				},
   555  			}, uc, newDummyStore(t))
   556  			init := time.Now()
   557  			compressionhelpers.Concurrently(uint64(switch_at), func(_, id uint64, _ *sync.Mutex) {
   558  				index.Add(uint64(id), vectors[id])
   559  			})
   560  			before = time.Now()
   561  			uc.PQ.Enabled = true
   562  			index.UpdateUserConfig(uc, func() {})
   563  			fmt.Printf("Time to compress: %s", time.Since(before))
   564  			fmt.Println()
   565  			compressionhelpers.Concurrently(uint64(vectors_size-switch_at), func(_, id uint64, _ *sync.Mutex) {
   566  				idx := switch_at + int(id)
   567  				index.Add(uint64(idx), vectors[idx])
   568  			})
   569  			fmt.Printf("Building the index took %s\n", time.Since(init))
   570  			var relevant uint64
   571  			var retrieved int
   572  
   573  			var querying time.Duration = 0
   574  			compressionhelpers.Concurrently(uint64(len(queries)), func(_, i uint64, _ *sync.Mutex) {
   575  				before = time.Now()
   576  				results, _, _ := index.SearchByVector(queries[i], k, nil)
   577  				querying += time.Since(before)
   578  				retrieved += k
   579  				relevant += testinghelpers.MatchesInLists(truths[i], results)
   580  			})
   581  
   582  			recall := float32(relevant) / float32(retrieved)
   583  			latency := float32(querying.Microseconds()) / float32(queries_size)
   584  			fmt.Println(recall, latency)
   585  			assert.True(t, recall > 0.9)
   586  			assert.True(t, latency < 100000)
   587  		}
   588  	}
   589  }
   590  
   591  func parseFromTxt(file string, size int) [][]float32 {
   592  	content, _ := ioutil.ReadFile(file)
   593  	strContent := string(content)
   594  	testArray := strings.Split(strContent, "\n")
   595  	test := make([][]float32, 0, len(testArray))
   596  	for j := 0; j < size; j++ {
   597  		elementArray := strings.Split(testArray[j], " ")
   598  		test = append(test, make([]float32, len(elementArray)))
   599  		for i := range elementArray {
   600  			f, _ := strconv.ParseFloat(elementArray[i], 16)
   601  			test[j][i] = float32(f)
   602  		}
   603  	}
   604  	return test
   605  }
   606  
   607  func newDummyStore(t *testing.T) *lsmkv.Store {
   608  	logger, _ := test.NewNullLogger()
   609  	storeDir := t.TempDir()
   610  	store, err := lsmkv.New(storeDir, storeDir, logger, nil,
   611  		cyclemanager.NewCallbackGroupNoop(), cyclemanager.NewCallbackGroupNoop())
   612  	require.Nil(t, err)
   613  	return store
   614  }