Skip to content

Commit 66ca292

Browse files
committed
vecindex: improve vector reranking
This commit exposes a new vector_search_rerank_multiplier session setting that controls how many vectors will be reranked at the end of a search. Empirical testing shows that for difficult datasets (e.g. Glove and CLIP), the number of vectors that need to be reranked is proportional to: log2(search_beam_size) * log2(top-k-results) We multiply this number by the vector_search_rerank_multiplier setting, which is set to 50 by default (also derived empirically). This formula will rerank enough vectors to allow us to achieve high accuracies while still providing a safeguard that prevents runaway evaluation in edge cases. Less difficult datasets need to rerank far fewer vectors, but it doesn't hurt to have a limit that's too high, since RaBitQ error bounds let us avoid actually evaluating unneeded vectors. This commit also increases the max value of vector_search_beam_size from 512 to 2048, since some datasets need it. Epic: CRDB-42943 Release note: None
1 parent bfb43f5 commit 66ca292

25 files changed

+252
-75
lines changed

pkg/cmd/vecbench/mem_provider.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,9 @@ func (m *MemProvider) Search(
165165
// Search the store.
166166
var idxCtx cspann.Context
167167
idxCtx.Init(txn)
168-
searchSet := cspann.SearchSet{MaxResults: memState.maxResults}
168+
maxResults, maxExtraResults :=
169+
cspann.IncreaseRerankResults(memState.beamSize, memState.maxResults, 50)
170+
searchSet := cspann.SearchSet{MaxResults: maxResults, MaxExtraResults: maxExtraResults}
169171
searchOptions := cspann.SearchOptions{BaseBeamSize: memState.beamSize}
170172
err = m.index.Search(ctx, &idxCtx, nil /* treeKey */, vec, &searchSet, searchOptions)
171173
if err != nil {

pkg/sql/exec_util.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4212,6 +4212,10 @@ func (m *sessionDataMutator) SetVectorSearchBeamSize(val int32) {
42124212
m.data.VectorSearchBeamSize = val
42134213
}
42144214

4215+
func (m *sessionDataMutator) SetVectorSearchRerankMultiplier(val int32) {
4216+
m.data.VectorSearchRerankMultiplier = val
4217+
}
4218+
42154219
func (m *sessionDataMutator) SetPropagateAdmissionHeaderToLeafTransactions(val bool) {
42164220
m.data.PropagateAdmissionHeaderToLeafTransactions = val
42174221
}

pkg/sql/logictest/testdata/logic_test/information_schema

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4141,6 +4141,7 @@ use_pre_25_2_variadic_builtins off
41414141
use_proc_txn_control_extended_protocol_fix on
41424142
variable_inequality_lookup_join_enabled on
41434143
vector_search_beam_size 32
4144+
vector_search_rerank_multiplier 50
41444145
xmloption content
41454146

41464147
# information_schema can be used with the anonymous database.

pkg/sql/logictest/testdata/logic_test/pg_catalog

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3146,6 +3146,7 @@ use_pre_25_2_variadic_builtins off
31463146
use_proc_txn_control_extended_protocol_fix on NULL NULL NULL string
31473147
variable_inequality_lookup_join_enabled on NULL NULL NULL string
31483148
vector_search_beam_size 32 NULL NULL NULL string
3149+
vector_search_rerank_multiplier 50 NULL NULL NULL string
31493150
vectorize on NULL NULL NULL string
31503151
xmloption content NULL NULL NULL string
31513152

@@ -3382,6 +3383,7 @@ use_pre_25_2_variadic_builtins off
33823383
use_proc_txn_control_extended_protocol_fix on NULL user NULL on on
33833384
variable_inequality_lookup_join_enabled on NULL user NULL on on
33843385
vector_search_beam_size 32 NULL user NULL 32 32
3386+
vector_search_rerank_multiplier 50 NULL user NULL 50 50
33853387
vectorize on NULL user NULL on on
33863388
xmloption content NULL user NULL content content
33873389

@@ -3610,6 +3612,7 @@ use_pre_25_2_variadic_builtins NULL NULL
36103612
use_proc_txn_control_extended_protocol_fix NULL NULL NULL NULL NULL
36113613
variable_inequality_lookup_join_enabled NULL NULL NULL NULL NULL
36123614
vector_search_beam_size NULL NULL NULL NULL NULL
3615+
vector_search_rerank_multiplier NULL NULL NULL NULL NULL
36133616
vectorize NULL NULL NULL NULL NULL
36143617
xmloption NULL NULL NULL NULL NULL
36153618

pkg/sql/logictest/testdata/logic_test/show_source

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ use_pre_25_2_variadic_builtins off
250250
use_proc_txn_control_extended_protocol_fix on
251251
variable_inequality_lookup_join_enabled on
252252
vector_search_beam_size 32
253+
vector_search_rerank_multiplier 50
253254
vectorize on
254255
xmloption content
255256

pkg/sql/logictest/testdata/logic_test/vector_index

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -843,11 +843,31 @@ SHOW vector_search_beam_size;
843843
----
844844
8
845845

846-
statement error vector_search_beam_size cannot be less than 1 or greater than 512
846+
statement error vector_search_beam_size cannot be less than 1 or greater than 2048
847847
SET vector_search_beam_size=0
848848

849-
statement error vector_search_beam_size cannot be less than 1 or greater than 512
850-
SET vector_search_beam_size=513
849+
statement error vector_search_beam_size cannot be less than 1 or greater than 2048
850+
SET vector_search_beam_size=2049
851+
852+
# Ensure that the vector_search_rerank_multiplier session setting is settable.
853+
query T
854+
SHOW vector_search_rerank_multiplier;
855+
----
856+
50
857+
858+
statement ok
859+
SET vector_search_rerank_multiplier=100
860+
861+
query T
862+
SHOW vector_search_rerank_multiplier;
863+
----
864+
100
865+
866+
statement error vector_search_rerank_multiplier cannot be less than 0 or greater than 100
867+
SET vector_search_rerank_multiplier=-1
868+
869+
statement error vector_search_rerank_multiplier cannot be less than 0 or greater than 100
870+
SET vector_search_rerank_multiplier=101
851871

852872
subtest end
853873

pkg/sql/rowexec/vector_search.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,9 @@ func newVectorSearchProcessor(
6161
}
6262
searchBeamSize := int(flowCtx.EvalCtx.SessionData().VectorSearchBeamSize)
6363
maxResults := int(v.targetCount)
64-
v.searcher.Init(flowCtx.EvalCtx, idx, flowCtx.Txn, &spec.GetFullVectorsFetchSpec, searchBeamSize, maxResults)
64+
rerankMultiplier := int(flowCtx.EvalCtx.SessionData().VectorSearchRerankMultiplier)
65+
v.searcher.Init(flowCtx.EvalCtx,
66+
idx, flowCtx.Txn, &spec.GetFullVectorsFetchSpec, searchBeamSize, maxResults, rerankMultiplier)
6567
colTypes := make([]*types.T, len(v.fetchSpec.FetchedColumns))
6668
for i, col := range v.fetchSpec.FetchedColumns {
6769
colTypes[i] = col.Type

pkg/sql/sessiondatapb/local_only_session_data.proto

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,11 @@ message LocalOnlySessionData {
694694
bool enable_scrub_job = 176;
695695
// AllowViewWithSecurityInvokerClause indicates whether security invoker for views is enabled
696696
bool allow_view_with_security_invoker_clause = 177;
697+
// VectorSearchRerankMultiplier controls how many of the initial search results
698+
// can be reranked using exact distance calculations with the original
699+
// full-size vectors. It acts as a multiplier on a base limit derived from the
700+
// search beam size and the top-k results requested by the query.
701+
int32 vector_search_rerank_multiplier = 178;
697702

698703
///////////////////////////////////////////////////////////////////////////
699704
// WARNING: consider whether a session parameter you're adding needs to //

pkg/sql/vars.go

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4047,9 +4047,9 @@ var varGen = map[string]sessionVar{
40474047
if err != nil {
40484048
return err
40494049
}
4050-
if b < 1 || b > 512 {
4050+
if b < 1 || b > 2048 {
40514051
return pgerror.Newf(pgcode.InvalidParameterValue,
4052-
"vector_search_beam_size cannot be less than 1 or greater than 512")
4052+
"vector_search_beam_size cannot be less than 1 or greater than 2048")
40534053
}
40544054
m.SetVectorSearchBeamSize(int32(b))
40554055
return nil
@@ -4062,6 +4062,29 @@ var varGen = map[string]sessionVar{
40624062
},
40634063
},
40644064

4065+
// CockroachDB extension.
4066+
`vector_search_rerank_multiplier`: {
4067+
GetStringVal: makeIntGetStringValFn(`vector_search_rerank_multiplier`),
4068+
Set: func(_ context.Context, m sessionDataMutator, s string) error {
4069+
b, err := strconv.ParseInt(s, 10, 32)
4070+
if err != nil {
4071+
return err
4072+
}
4073+
if b < 0 || b > 100 {
4074+
return pgerror.Newf(pgcode.InvalidParameterValue,
4075+
"vector_search_rerank_multiplier cannot be less than 0 or greater than 100")
4076+
}
4077+
m.SetVectorSearchRerankMultiplier(int32(b))
4078+
return nil
4079+
},
4080+
Get: func(evalCtx *extendedEvalContext, _ *kv.Txn) (string, error) {
4081+
return strconv.FormatInt(int64(evalCtx.SessionData().VectorSearchRerankMultiplier), 10), nil
4082+
},
4083+
GlobalDefault: func(sv *settings.Values) string {
4084+
return "50"
4085+
},
4086+
},
4087+
40654088
// CockroachDB extension.
40664089
`propagate_admission_header_to_leaf_transactions`: {
40674090
GetStringVal: makePostgresBoolGetStringValFn(`propagate_admission_header_to_leaf_transactions`),

pkg/sql/vecindex/cspann/index.go

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,6 @@ import (
2525
"github.com/cockroachdb/errors"
2626
)
2727

28-
// RerankMultiplier is multiplied by MaxResults to calculate the maximum number
29-
// of search results that will be reranked with the original full-size vectors.
30-
const RerankMultiplier = 10
31-
3228
// DeletedMinCount sets a minimum number of results that will be reranked, in
3329
// order to account for vectors that may have been deleted in the primary index.
3430
const DeletedMinCount = 10
@@ -41,18 +37,30 @@ const DeletedMultiplier = 1.2
4137
// MaxQualitySamples specifies the max value of the QualitySamples index option.
4238
const MaxQualitySamples = 32
4339

44-
// IncreaseRerankResults returns good values for maxResults and maxExtraResults
45-
// that have a high probability of returning the desired number of results, even
46-
// when there are deleted results. Deleted results will be filtered out by the
47-
// rerank process, so we need to make sure there are additional results that can
48-
// be returned instead.
40+
// IncreaseRerankResults returns good values for maxResults and maxExtraResults.
41+
// Deleted results will be filtered out of the final results, so we need to make
42+
// sure there are additional results that can be returned instead. In addition,
43+
// quantization error can reduce the accuracy of results, so we need to return
44+
// extra results that can be reranked by exact distance calculations. Both the
45+
// search beam size and the top-k limit of results emperically have a
46+
// logarithmic relationship to the number of vectors that need to be reranked,
47+
// so use this formula to set a bound to the number of extra results:
48+
//
49+
// maxExtraResults =
50+
// log2(searchBeamSize) * log2(desiredMaxResults) * rerankMultiplier
51+
//
52+
// The rerank multiplier is a session setting that can be used to set a tighter
53+
// or looser bound.
4954
//
5055
// TODO(andyk): Switch the index to use a search iterator so the caller can keep
5156
// requesting further results rather than guessing at how many additional
5257
// results might be needed.
53-
func IncreaseRerankResults(desiredMaxResults int) (maxResults, maxExtraResults int) {
58+
func IncreaseRerankResults(
59+
searchBeamSize, desiredMaxResults, rerankMultiplier int,
60+
) (maxResults, maxExtraResults int) {
5461
maxResults = max(int(math.Ceil(float64(desiredMaxResults)*DeletedMultiplier)), DeletedMinCount)
55-
maxExtraResults = desiredMaxResults * RerankMultiplier
62+
log := math.Log2(float64(max(searchBeamSize, 2))) * math.Log2(float64(max(desiredMaxResults, 2)))
63+
maxExtraResults = int(log) * rerankMultiplier
5664
return maxResults, maxExtraResults
5765
}
5866

0 commit comments

Comments
 (0)