@@ -26,11 +26,20 @@ using namespace NYdb::NTable;
26
26
27
27
Y_UNIT_TEST_SUITE (KqpPrefixedVectorIndexes) {
28
28
29
- std::vector<i64> DoPositiveQueryVectorIndex (TSession& session, const TString& query) {
29
+ std::vector<i64> DoPositiveQueryVectorIndex (TSession& session, const TString& query, bool covered = false ) {
30
30
{
31
31
auto result = session.ExplainDataQuery (query).ExtractValueSync ();
32
32
UNIT_ASSERT_C (result.IsSuccess (),
33
33
" Failed to explain: `" << query << " ` with " << result.GetIssues ().ToString ());
34
+
35
+ if (covered) {
36
+ // Check that the query doesn't use main table
37
+ NJson::TJsonValue plan;
38
+ NJson::ReadJsonTree (result.GetPlan (), &plan, true );
39
+ UNIT_ASSERT (ValidatePlanNodeIds (plan));
40
+ auto mainTableAccess = CountPlanNodesByKv (plan, " Table" , " TestTable" );
41
+ UNIT_ASSERT_VALUES_EQUAL (mainTableAccess, 0 );
42
+ }
34
43
}
35
44
{
36
45
auto result = session.ExecuteDataQuery (query,
@@ -53,7 +62,7 @@ Y_UNIT_TEST_SUITE(KqpPrefixedVectorIndexes) {
53
62
}
54
63
}
55
64
56
- void DoPositiveQueriesVectorIndex (TSession& session, const TString& mainQuery, const TString& indexQuery) {
65
+ void DoPositiveQueriesVectorIndex (TSession& session, const TString& mainQuery, const TString& indexQuery, bool covered = false ) {
57
66
auto toStr = [](const auto & rs) -> TString {
58
67
TStringBuilder b;
59
68
for (const auto & r : rs) {
@@ -66,7 +75,7 @@ Y_UNIT_TEST_SUITE(KqpPrefixedVectorIndexes) {
66
75
UNIT_ASSERT_EQUAL_C (mainResults.size (), 3 , toStr (mainResults));
67
76
UNIT_ASSERT_C (std::unique (mainResults.begin (), mainResults.end ()) == mainResults.end (), toStr (mainResults));
68
77
69
- auto indexResults = DoPositiveQueryVectorIndex (session, indexQuery);
78
+ auto indexResults = DoPositiveQueryVectorIndex (session, indexQuery, covered );
70
79
absl::c_sort (indexResults);
71
80
UNIT_ASSERT_EQUAL_C (indexResults.size (), 3 , toStr (indexResults));
72
81
UNIT_ASSERT_C (std::unique (indexResults.begin (), indexResults.end ()) == indexResults.end (), toStr (indexResults));
@@ -79,13 +88,17 @@ Y_UNIT_TEST_SUITE(KqpPrefixedVectorIndexes) {
79
88
std::string_view function,
80
89
std::string_view direction,
81
90
std::string_view left,
82
- std::string_view right) {
91
+ std::string_view right,
92
+ bool covered = false ) {
83
93
constexpr std::string_view init =
84
94
" $target = \"\x67\x68\x03\" ;\n "
85
95
" $user = \" user_b\" ;" ;
86
96
std::string metric = std::format (" Knn::{}({}, {})" , function, left, right);
87
97
// no metric in result
88
98
{
99
+ // TODO(vitaliff): Exclude index-covered WHERE fields from KqpReadTableRanges.
100
+ // Currently even if we SELECT only pk, emb, data WHERE user=xxx we also get `user`
101
+ // in SELECT columns and thus it's required to add it to covered columns.
89
102
const TString plainQuery (Q1_ (std::format (R"( {}
90
103
SELECT * FROM `/Root/TestTable`
91
104
WHERE user = $user
@@ -100,7 +113,7 @@ Y_UNIT_TEST_SUITE(KqpPrefixedVectorIndexes) {
100
113
ORDER BY {} {}
101
114
LIMIT 3;
102
115
)" , init, metric, direction)));
103
- DoPositiveQueriesVectorIndex (session, plainQuery, indexQuery);
116
+ DoPositiveQueriesVectorIndex (session, plainQuery, indexQuery, covered );
104
117
}
105
118
// metric in result
106
119
{
@@ -117,7 +130,7 @@ Y_UNIT_TEST_SUITE(KqpPrefixedVectorIndexes) {
117
130
ORDER BY {} {}
118
131
LIMIT 3;
119
132
)" , init, metric, metric, direction)));
120
- DoPositiveQueriesVectorIndex (session, plainQuery, indexQuery);
133
+ DoPositiveQueriesVectorIndex (session, plainQuery, indexQuery, covered );
121
134
}
122
135
// metric as result
123
136
// TODO(mbkkt) fix this behavior too
@@ -136,27 +149,28 @@ Y_UNIT_TEST_SUITE(KqpPrefixedVectorIndexes) {
136
149
ORDER BY m {}
137
150
LIMIT 3;
138
151
)" , init, metric, direction)));
139
- DoPositiveQueriesVectorIndex (session, plainQuery, indexQuery);
152
+ DoPositiveQueriesVectorIndex (session, plainQuery, indexQuery, covered );
140
153
}
141
154
}
142
155
143
156
void DoPositiveQueriesPrefixedVectorIndexOrderBy (
144
157
TSession& session,
145
158
std::string_view function,
146
- std::string_view direction) {
159
+ std::string_view direction,
160
+ bool covered = false ) {
147
161
// target is left, member is right
148
- DoPositiveQueriesPrefixedVectorIndexOrderBy (session, function, direction, " $target" , " emb" );
162
+ DoPositiveQueriesPrefixedVectorIndexOrderBy (session, function, direction, " $target" , " emb" , covered );
149
163
// target is right, member is left
150
- DoPositiveQueriesPrefixedVectorIndexOrderBy (session, function, direction, " emb" , " $target" );
164
+ DoPositiveQueriesPrefixedVectorIndexOrderBy (session, function, direction, " emb" , " $target" , covered );
151
165
}
152
166
153
- void DoPositiveQueriesPrefixedVectorIndexOrderByCosine (TSession& session) {
167
+ void DoPositiveQueriesPrefixedVectorIndexOrderByCosine (TSession& session, bool covered = false ) {
154
168
// distance, default direction
155
- DoPositiveQueriesPrefixedVectorIndexOrderBy (session, " CosineDistance" , " " );
169
+ DoPositiveQueriesPrefixedVectorIndexOrderBy (session, " CosineDistance" , " " , covered );
156
170
// distance, asc direction
157
- DoPositiveQueriesPrefixedVectorIndexOrderBy (session, " CosineDistance" , " ASC" );
171
+ DoPositiveQueriesPrefixedVectorIndexOrderBy (session, " CosineDistance" , " ASC" , covered );
158
172
// similarity, desc direction
159
- DoPositiveQueriesPrefixedVectorIndexOrderBy (session, " CosineSimilarity" , " DESC" );
173
+ DoPositiveQueriesPrefixedVectorIndexOrderBy (session, " CosineSimilarity" , " DESC" , covered );
160
174
}
161
175
162
176
TSession DoCreateTableForPrefixedVectorIndex (TTableClient& db, bool nullable) {
@@ -406,6 +420,7 @@ Y_UNIT_TEST_SUITE(KqpPrefixedVectorIndexes) {
406
420
.ExtractValueSync ();
407
421
408
422
UNIT_ASSERT_C (result.IsSuccess (), result.GetIssues ().ToString ());
423
+ // FIXME: result does not return failure/issues when index is created but fails to be filled with data
409
424
}
410
425
{
411
426
auto result = session.DescribeTable (" /Root/TestTable" ).ExtractValueSync ();
@@ -425,6 +440,54 @@ Y_UNIT_TEST_SUITE(KqpPrefixedVectorIndexes) {
425
440
DoPositiveQueriesPrefixedVectorIndexOrderByCosine (session);
426
441
}
427
442
443
+ Y_UNIT_TEST_TWIN (PrefixedVectorIndexOrderByCosineDistanceWithCover, Nullable) {
444
+ NKikimrConfig::TFeatureFlags featureFlags;
445
+ featureFlags.SetEnableVectorIndex (true );
446
+ auto setting = NKikimrKqp::TKqpSetting ();
447
+ auto serverSettings = TKikimrSettings ()
448
+ .SetFeatureFlags (featureFlags)
449
+ .SetKqpSettings ({setting});
450
+
451
+ TKikimrRunner kikimr (serverSettings);
452
+ kikimr.GetTestServer ().GetRuntime ()->SetLogPriority (NKikimrServices::BUILD_INDEX, NActors::NLog::PRI_TRACE);
453
+ kikimr.GetTestServer ().GetRuntime ()->SetLogPriority (NKikimrServices::FLAT_TX_SCHEMESHARD, NActors::NLog::PRI_TRACE);
454
+
455
+ auto db = kikimr.GetTableClient ();
456
+ auto session = DoCreateTableForPrefixedVectorIndex (db, Nullable);
457
+ {
458
+ const TString createIndex (Q_ (R"(
459
+ ALTER TABLE `/Root/TestTable`
460
+ ADD INDEX index
461
+ GLOBAL USING vector_kmeans_tree
462
+ ON (user, emb) COVER (user, emb, data)
463
+ WITH (distance=cosine, vector_type="uint8", vector_dimension=2, levels=2, clusters=2);
464
+ )" ));
465
+
466
+ auto result = session.ExecuteSchemeQuery (createIndex)
467
+ .ExtractValueSync ();
468
+
469
+ UNIT_ASSERT_C (result.IsSuccess (), result.GetIssues ().ToString ());
470
+ }
471
+ {
472
+ auto result = session.DescribeTable (" /Root/TestTable" ).ExtractValueSync ();
473
+ UNIT_ASSERT_VALUES_EQUAL (result.GetStatus (), NYdb::EStatus::SUCCESS);
474
+ const auto & indexes = result.GetTableDescription ().GetIndexDescriptions ();
475
+ UNIT_ASSERT_EQUAL (indexes.size (), 1 );
476
+ UNIT_ASSERT_EQUAL (indexes[0 ].GetIndexName (), " index" );
477
+ std::vector<std::string> indexKeyColumns{" user" , " emb" };
478
+ UNIT_ASSERT_EQUAL (indexes[0 ].GetIndexColumns (), indexKeyColumns);
479
+ std::vector<std::string> indexDataColumns{" user" , " emb" , " data" };
480
+ UNIT_ASSERT_EQUAL (indexes[0 ].GetDataColumns (), indexDataColumns);
481
+ const auto & settings = std::get<TKMeansTreeSettings>(indexes[0 ].GetIndexSettings ());
482
+ UNIT_ASSERT_EQUAL (settings.Settings .Metric , NYdb::NTable::TVectorIndexSettings::EMetric::CosineDistance);
483
+ UNIT_ASSERT_EQUAL (settings.Settings .VectorType , NYdb::NTable::TVectorIndexSettings::EVectorType::Uint8);
484
+ UNIT_ASSERT_EQUAL (settings.Settings .VectorDimension , 2 );
485
+ UNIT_ASSERT_EQUAL (settings.Levels , 2 );
486
+ UNIT_ASSERT_EQUAL (settings.Clusters , 2 );
487
+ }
488
+ DoPositiveQueriesPrefixedVectorIndexOrderByCosine (session, true /* covered*/ );
489
+ }
490
+
428
491
}
429
492
430
493
}
0 commit comments