Skip to content

Commit 15ef013

Browse files
garvit-guptaCarmenPopoviciuemily-shenedmundhung
authored
VS-284: Add Wrangler support for QueryById (#7004)
* VS-284: Enable query by id via Wrangler * Apply suggestions from code review Co-authored-by: Carmen Popoviciu <[email protected]> * Update .changeset/happy-scissors-deliver.md Co-authored-by: Edmund Hung <[email protected]> --------- Co-authored-by: Carmen Popoviciu <[email protected]> Co-authored-by: emily-shen <[email protected]> Co-authored-by: Edmund Hung <[email protected]>
1 parent a33a133 commit 15ef013

File tree

4 files changed

+142
-117
lines changed

4 files changed

+142
-117
lines changed

.changeset/happy-scissors-deliver.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"wrangler": minor
3+
---
4+
5+
feat: Enable Vectorize query by id via Wrangler

packages/wrangler/src/__tests__/vectorize/vectorize.test.ts

+80-112
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,8 @@ describe("vectorize help", () => {
173173
-v, --version Show version number [boolean]
174174
175175
OPTIONS
176-
--vector Vector to query the Vectorize Index [array] [required]
176+
--vector Vector to query the Vectorize Index [array]
177+
--vector-id Identifier for a vector in the index against which the index should be queried [string]
177178
--top-k The number of results (nearest neighbors) to return [number] [default: 5]
178179
--return-values Specify if the vector values should be included in the results [boolean] [default: false]
179180
--return-metadata Specify if the vector metadata should be included in the results [string] [choices: \\"all\\", \\"indexed\\", \\"none\\"] [default: \\"none\\"]
@@ -523,87 +524,25 @@ describe("vectorize commands", () => {
523524
await runWrangler(
524525
"vectorize query test-index --vector 1 2 3 '4' 1.5 '2.6' a 'b' null 7 abc 8 undefined"
525526
);
526-
expect(std.out).toMatchInlineSnapshot(`
527-
"📋 Searching for relevant vectors...
528-
{
529-
\\"count\\": 2,
530-
\\"matches\\": [
531-
{
532-
\\"id\\": \\"a\\",
533-
\\"score\\": 0.5,
534-
\\"values\\": [
535-
1,
536-
2,
537-
3,
538-
4
539-
],
540-
\\"namespace\\": \\"abcd\\",
541-
\\"metadata\\": {
542-
\\"a\\": true,
543-
\\"b\\": 123
544-
}
545-
},
546-
{
547-
\\"id\\": \\"b\\",
548-
\\"score\\": 0.75,
549-
\\"values\\": [
550-
5,
551-
6,
552-
7,
553-
8
554-
],
555-
\\"metadata\\": {
556-
\\"c\\": false,
557-
\\"b\\": \\"123\\"
558-
}
559-
}
560-
]
561-
}"
562-
`);
527+
expect(std.out).toMatchInlineSnapshot(querySnapshot);
528+
});
529+
530+
it("should handle a query with a vector-id", async () => {
531+
mockVectorizeV2Request();
532+
await runWrangler("vectorize query test-index --vector-id some-vector-id");
533+
expect(std.out).toMatchInlineSnapshot(querySnapshot);
534+
535+
// No warning or error
536+
expect(std.warn).toMatchInlineSnapshot(`""`);
537+
expect(std.err).toMatchInlineSnapshot(`""`);
563538
});
564539

565540
it("should handle a query on a vectorize index with all options", async () => {
566541
mockVectorizeV2Request();
567542
await runWrangler(
568543
`vectorize query test-index --vector 1 2 3 '4' --top-k=2 --return-values=true --return-metadata=indexed --namespace=abc --filter '{ "p1": "abc", "p2": { "$ne": true }, "p3": 10, "p4": false, "nested.p5": "abcd" }'`
569544
);
570-
expect(std.out).toMatchInlineSnapshot(`
571-
"📋 Searching for relevant vectors...
572-
{
573-
\\"count\\": 2,
574-
\\"matches\\": [
575-
{
576-
\\"id\\": \\"a\\",
577-
\\"score\\": 0.5,
578-
\\"values\\": [
579-
1,
580-
2,
581-
3,
582-
4
583-
],
584-
\\"namespace\\": \\"abcd\\",
585-
\\"metadata\\": {
586-
\\"a\\": true,
587-
\\"b\\": 123
588-
}
589-
},
590-
{
591-
\\"id\\": \\"b\\",
592-
\\"score\\": 0.75,
593-
\\"values\\": [
594-
5,
595-
6,
596-
7,
597-
8
598-
],
599-
\\"metadata\\": {
600-
\\"c\\": false,
601-
\\"b\\": \\"123\\"
602-
}
603-
}
604-
]
605-
}"
606-
`);
545+
expect(std.out).toMatchInlineSnapshot(querySnapshot);
607546

608547
// No warning > Valid filter
609548
expect(std.warn).toMatchInlineSnapshot(`""`);
@@ -614,43 +553,7 @@ describe("vectorize commands", () => {
614553
await runWrangler(
615554
"vectorize query test-index --vector 1 2 3 '4' --filter='{ 'p1': [1,2,3] }'"
616555
);
617-
expect(std.out).toMatchInlineSnapshot(`
618-
"📋 Searching for relevant vectors...
619-
{
620-
\\"count\\": 2,
621-
\\"matches\\": [
622-
{
623-
\\"id\\": \\"a\\",
624-
\\"score\\": 0.5,
625-
\\"values\\": [
626-
1,
627-
2,
628-
3,
629-
4
630-
],
631-
\\"namespace\\": \\"abcd\\",
632-
\\"metadata\\": {
633-
\\"a\\": true,
634-
\\"b\\": 123
635-
}
636-
},
637-
{
638-
\\"id\\": \\"b\\",
639-
\\"score\\": 0.75,
640-
\\"values\\": [
641-
5,
642-
6,
643-
7,
644-
8
645-
],
646-
\\"metadata\\": {
647-
\\"c\\": false,
648-
\\"b\\": \\"123\\"
649-
}
650-
}
651-
]
652-
}"
653-
`);
556+
expect(std.out).toMatchInlineSnapshot(querySnapshot);
654557

655558
expect(std.warn).toMatchInlineSnapshot(`
656559
"▲ [WARNING] 🚨 Invalid query filter. Please use the recommended format.
@@ -669,6 +572,34 @@ describe("vectorize commands", () => {
669572
expect(std.warn).toMatchInlineSnapshot(`
670573
"▲ [WARNING] Could not find any relevant vectors
671574
575+
"
576+
`);
577+
});
578+
579+
it("should fail query when neither vector nor vector-id is provided", async () => {
580+
mockVectorizeV2RequestError();
581+
await runWrangler(
582+
"vectorize query test-index --top-k=2 --return-values=true"
583+
);
584+
expect(std.out).toMatchInlineSnapshot(`""`);
585+
586+
expect(std.err).toMatchInlineSnapshot(`
587+
"X [ERROR] 🚨 Either vector or vector-id parameter must be provided, but not both.
588+
589+
"
590+
`);
591+
});
592+
593+
it("should fail query when both vector and vector-id are provided", async () => {
594+
mockVectorizeV2RequestError();
595+
await runWrangler(
596+
"vectorize query test-index --vector 1 2 3 '4' --vector-id some-vector-id"
597+
);
598+
expect(std.out).toMatchInlineSnapshot(`""`);
599+
600+
expect(std.err).toMatchInlineSnapshot(`
601+
"X [ERROR] 🚨 Either vector or vector-id parameter must be provided, but not both.
602+
672603
"
673604
`);
674605
});
@@ -866,6 +797,43 @@ describe("vectorize query filter", () => {
866797
});
867798
});
868799

800+
const querySnapshot = `
801+
"📋 Searching for relevant vectors...
802+
{
803+
\\"count\\": 2,
804+
\\"matches\\": [
805+
{
806+
\\"id\\": \\"a\\",
807+
\\"score\\": 0.5,
808+
\\"values\\": [
809+
1,
810+
2,
811+
3,
812+
4
813+
],
814+
\\"namespace\\": \\"abcd\\",
815+
\\"metadata\\": {
816+
\\"a\\": true,
817+
\\"b\\": 123
818+
}
819+
},
820+
{
821+
\\"id\\": \\"b\\",
822+
\\"score\\": 0.75,
823+
\\"values\\": [
824+
5,
825+
6,
826+
7,
827+
8
828+
],
829+
\\"metadata\\": {
830+
\\"c\\": false,
831+
\\"b\\": \\"123\\"
832+
}
833+
}
834+
]
835+
}"`;
836+
869837
/** Create a mock handler for the Vectorize API */
870838
function mockVectorizeRequest() {
871839
msw.use(

packages/wrangler/src/vectorize/client.ts

+23-1
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ export async function upsertIntoIndex(
131131
);
132132
}
133133

134-
export async function queryIndex(
134+
export async function queryIndexByVector(
135135
config: Config,
136136
indexName: string,
137137
vector: VectorFloatArray | number[],
@@ -153,6 +153,28 @@ export async function queryIndex(
153153
);
154154
}
155155

156+
export async function queryIndexByVectorId(
157+
config: Config,
158+
indexName: string,
159+
vectorId: string,
160+
options: VectorizeQueryOptions
161+
): Promise<VectorizeMatches> {
162+
const accountId = await requireAuth(config);
163+
return await fetchResult(
164+
`/accounts/${accountId}/vectorize/v2/indexes/${indexName}/query`,
165+
{
166+
method: "POST",
167+
headers: {
168+
"content-type": jsonContentType,
169+
},
170+
body: JSON.stringify({
171+
...options,
172+
vectorId,
173+
}),
174+
}
175+
);
176+
}
177+
156178
export async function getByIds(
157179
config: Config,
158180
indexName: string,

packages/wrangler/src/vectorize/query.ts

+34-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { readConfig } from "../config";
22
import { logger } from "../logger";
3-
import { queryIndex } from "./client";
3+
import { queryIndexByVector, queryIndexByVectorId } from "./client";
44
import { vectorizeGABanner } from "./common";
55
import type {
66
CommonYargsArgv,
77
StrictYargsOptionsToInterface,
88
} from "../yargs-types";
99
import type {
10+
VectorizeMatches,
1011
VectorizeMetadataFilterInnerValue,
1112
VectorizeMetadataFilterValue,
1213
VectorizeMetadataRetrievalLevel,
@@ -26,7 +27,6 @@ export function options(yargs: CommonYargsArgv) {
2627
.options({
2728
vector: {
2829
type: "array",
29-
demandOption: true,
3030
describe: "Vector to query the Vectorize Index",
3131
coerce: (arg: unknown[]) =>
3232
arg
@@ -38,6 +38,11 @@ export function options(yargs: CommonYargsArgv) {
3838
typeof value === "number" && !isNaN(value)
3939
),
4040
},
41+
"vector-id": {
42+
type: "string",
43+
describe:
44+
"Identifier for a vector in the index against which the index should be queried",
45+
},
4146
"top-k": {
4247
type: "number",
4348
default: 5,
@@ -114,10 +119,35 @@ export async function handler(
114119
}
115120
}
116121

122+
if (
123+
(args.vector === undefined && args.vectorId === undefined) ||
124+
(args.vector !== undefined && args.vectorId !== undefined)
125+
) {
126+
logger.error(
127+
"🚨 Either vector or vector-id parameter must be provided, but not both."
128+
);
129+
return;
130+
}
131+
117132
logger.log(`📋 Searching for relevant vectors...`);
118-
const res = await queryIndex(config, args.name, args.vector, queryOptions);
133+
let res: VectorizeMatches | undefined;
134+
if (args.vector !== undefined) {
135+
res = await queryIndexByVector(
136+
config,
137+
args.name,
138+
args.vector,
139+
queryOptions
140+
);
141+
} else if (args.vectorId !== undefined) {
142+
res = await queryIndexByVectorId(
143+
config,
144+
args.name,
145+
args.vectorId,
146+
queryOptions
147+
);
148+
}
119149

120-
if (res.count === 0) {
150+
if (res === undefined || res.count === 0) {
121151
logger.warn(`Could not find any relevant vectors`);
122152
return;
123153
}

0 commit comments

Comments
 (0)