Skip to content

Commit e906b42

Browse files
feat: Vector Search (#2006)
Support Vector Search --------- Co-authored-by: wu-hui <[email protected]>
1 parent d2d6bcb commit e906b42

20 files changed

+2777
-425
lines changed

api-report/firestore.api.md

Lines changed: 108 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,7 @@ export class FieldValue implements firestore.FieldValue {
717717
// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@"
718718
// Warning: (tsdoc-undefined-tag) The TSDoc tag "@return" is not defined in this configuration
719719
static serverTimestamp(): FieldValue;
720+
static vector(values?: number[]): VectorValue;
720721
}
721722

722723
// @public
@@ -1003,6 +1004,10 @@ export class Query<AppModelType = firestore.DocumentData, DbModelType extends fi
10031004
count(): AggregateQuery<{
10041005
count: firestore.AggregateField<number>;
10051006
}, AppModelType, DbModelType>;
1007+
// Warning: (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
1008+
//
1009+
// @internal
1010+
_createSnapshot(readTime: Timestamp, size: number, docs: () => Array<QueryDocumentSnapshot<AppModelType, DbModelType>>, changes: () => Array<DocumentChange<AppModelType, DbModelType>>): QuerySnapshot<AppModelType, DbModelType>;
10061011
// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
10071012
// Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}'
10081013
// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag
@@ -1028,6 +1033,10 @@ export class Query<AppModelType = firestore.DocumentData, DbModelType extends fi
10281033
//
10291034
// @internal
10301035
static _extractFieldValues(documentSnapshot: DocumentSnapshot, fieldOrders: FieldOrder[]): unknown[];
1036+
findNearest(vectorField: string | firestore.FieldPath, queryVector: firestore.VectorValue | Array<number>, options: {
1037+
limit: number;
1038+
distanceMeasure: 'EUCLIDEAN' | 'COSINE' | 'DOT_PRODUCT';
1039+
}): VectorQuery<AppModelType, DbModelType>;
10311040
// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag
10321041
// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@"
10331042
// Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration
@@ -1047,7 +1056,7 @@ export class Query<AppModelType = firestore.DocumentData, DbModelType extends fi
10471056
_get(transactionIdOrReadTime?: Uint8Array | Timestamp): Promise<QuerySnapshot<AppModelType, DbModelType>>;
10481057
// Warning: (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
10491058
//
1050-
// @internal (undocumented)
1059+
// @internal
10511060
_hasRetryTimedOut(methodName: string, startTime: number): boolean;
10521061
// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
10531062
// Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}'
@@ -1106,12 +1115,21 @@ export class Query<AppModelType = firestore.DocumentData, DbModelType extends fi
11061115
// Warning: (ae-forgotten-export) The symbol "QueryOptions" needs to be exported by the entry point index.d.ts
11071116
//
11081117
// @internal (undocumented)
1109-
protected readonly _queryOptions: QueryOptions<AppModelType, DbModelType>;
1118+
readonly _queryOptions: QueryOptions<AppModelType, DbModelType>;
1119+
// Warning: (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
1120+
// Warning: (ae-forgotten-export) The symbol "QueryUtil" needs to be exported by the entry point index.d.ts
1121+
//
1122+
// @internal (undocumented)
1123+
readonly _queryUtil: QueryUtil<AppModelType, DbModelType, Query<AppModelType, DbModelType>>;
11101124
// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
11111125
// Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}'
11121126
// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag
11131127
// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@"
11141128
select(...fieldPaths: Array<string | FieldPath>): Query;
1129+
// Warning: (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
1130+
//
1131+
// @internal (undocumented)
1132+
readonly _serializer: Serializer;
11151133
// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
11161134
// Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}'
11171135
// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag
@@ -1424,6 +1442,74 @@ export class Transaction implements firestore.Transaction {
14241442
update<AppModelType, DbModelType extends firestore.DocumentData>(documentRef: firestore.DocumentReference<AppModelType, DbModelType>, dataOrField: firestore.UpdateData<DbModelType> | string | firestore.FieldPath, ...preconditionOrValues: Array<firestore.Precondition | unknown | string | firestore.FieldPath>): Transaction;
14251443
}
14261444

1445+
// @public
1446+
export class VectorQuery<AppModelType = firestore.DocumentData, DbModelType extends firestore.DocumentData = firestore.DocumentData> implements firestore.VectorQuery<AppModelType, DbModelType> {
1447+
// Warning: (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
1448+
// Warning: (ae-forgotten-export) The symbol "VectorQueryOptions" needs to be exported by the entry point index.d.ts
1449+
//
1450+
// @internal
1451+
constructor(_query: Query<AppModelType, DbModelType>, vectorField: string | firestore.FieldPath, queryVector: firestore.VectorValue | Array<number>, options: VectorQueryOptions);
1452+
// Warning: (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
1453+
//
1454+
// @internal
1455+
_createSnapshot(readTime: Timestamp, size: number, docs: () => Array<QueryDocumentSnapshot<AppModelType, DbModelType>>, changes: () => Array<DocumentChange<AppModelType, DbModelType>>): VectorQuerySnapshot<AppModelType, DbModelType>;
1456+
get(): Promise<VectorQuerySnapshot<AppModelType, DbModelType>>;
1457+
isEqual(other: firestore.VectorQuery<AppModelType, DbModelType>): boolean;
1458+
get query(): Query<AppModelType, DbModelType>;
1459+
// Warning: (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
1460+
//
1461+
// @internal (undocumented)
1462+
readonly _queryUtil: QueryUtil<AppModelType, DbModelType, VectorQuery<AppModelType, DbModelType>>;
1463+
// Warning: (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
1464+
//
1465+
// @internal
1466+
startAfter(...fieldValuesOrDocumentSnapshot: Array<unknown>): VectorQuery<AppModelType, DbModelType>;
1467+
// Warning: (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
1468+
//
1469+
// @internal
1470+
_stream(transactionId?: Uint8Array): NodeJS.ReadableStream;
1471+
// Warning: (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
1472+
//
1473+
// @internal
1474+
toProto(transactionIdOrReadTime?: Uint8Array | Timestamp): api.IRunQueryRequest;
1475+
}
1476+
1477+
// @public
1478+
export class VectorQuerySnapshot<AppModelType = firestore.DocumentData, DbModelType extends firestore.DocumentData = firestore.DocumentData> implements firestore.VectorQuerySnapshot<AppModelType, DbModelType> {
1479+
// Warning: (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
1480+
//
1481+
// @internal
1482+
constructor(_query: VectorQuery<AppModelType, DbModelType>, _readTime: Timestamp, _size: number, docs: () => Array<QueryDocumentSnapshot<AppModelType, DbModelType>>, changes: () => Array<DocumentChange<AppModelType, DbModelType>>);
1483+
docChanges(): Array<DocumentChange<AppModelType, DbModelType>>;
1484+
get docs(): Array<QueryDocumentSnapshot<AppModelType, DbModelType>>;
1485+
get empty(): boolean;
1486+
forEach(callback: (result: firestore.QueryDocumentSnapshot<AppModelType, DbModelType>) => void, thisArg?: unknown): void;
1487+
isEqual(other: firestore.VectorQuerySnapshot<AppModelType, DbModelType>): boolean;
1488+
get query(): VectorQuery<AppModelType, DbModelType>;
1489+
get readTime(): Timestamp;
1490+
get size(): number;
1491+
}
1492+
1493+
// Warning: (tsdoc-undefined-tag) The TSDoc tag "@class" is not defined in this configuration
1494+
//
1495+
// @public
1496+
export class VectorValue implements firestore.VectorValue {
1497+
// Warning: (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
1498+
//
1499+
// @internal
1500+
constructor(values: number[] | undefined);
1501+
// Warning: (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
1502+
//
1503+
// @internal (undocumented)
1504+
static _fromProto(valueArray: api.IValue): VectorValue;
1505+
isEqual(other: VectorValue): boolean;
1506+
toArray(): number[];
1507+
// Warning: (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
1508+
//
1509+
// @internal (undocumented)
1510+
_toProto(serializer: Serializer): api.IValue;
1511+
}
1512+
14271513
// Warning: (tsdoc-undefined-tag) The TSDoc tag "@class" is not defined in this configuration
14281514
//
14291515
// @public
@@ -1570,24 +1656,26 @@ export class WriteResult implements firestore.WriteResult {
15701656
// build/src/reference.d.ts:367:4 - (tsdoc-undefined-tag) The TSDoc tag "@class" is not defined in this configuration
15711657
// build/src/reference.d.ts:398:4 - (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
15721658
// build/src/reference.d.ts:400:4 - (tsdoc-undefined-tag) The TSDoc tag "@class" is not defined in this configuration
1573-
// build/src/reference.d.ts:629:4 - (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
1574-
// build/src/reference.d.ts:999:8 - (tsdoc-undefined-tag) The TSDoc tag "@return" is not defined in this configuration
1575-
// build/src/reference.d.ts:1005:8 - (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
1576-
// build/src/reference.d.ts:1007:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
1577-
// build/src/reference.d.ts:1015:8 - (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
1578-
// build/src/reference.d.ts:1017:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
1579-
// build/src/reference.d.ts:1017:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}'
1580-
// build/src/reference.d.ts:1019:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
1581-
// build/src/reference.d.ts:1019:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}'
1582-
// build/src/reference.d.ts:1021:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
1583-
// build/src/reference.d.ts:1023:24 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag
1584-
// build/src/reference.d.ts:1023:17 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@"
1585-
// build/src/reference.d.ts:1032:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
1586-
// build/src/reference.d.ts:1034:8 - (tsdoc-undefined-tag) The TSDoc tag "@return" is not defined in this configuration
1587-
// build/src/reference.d.ts:1036:8 - (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
1588-
// build/src/reference.d.ts:1220:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
1589-
// build/src/reference.d.ts:1221:8 - (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
1590-
// build/src/reference.d.ts:1478:8 - (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
1659+
// build/src/reference.d.ts:800:4 - (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
1660+
// build/src/reference.d.ts:1228:8 - (tsdoc-undefined-tag) The TSDoc tag "@return" is not defined in this configuration
1661+
// build/src/reference.d.ts:1234:8 - (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
1662+
// build/src/reference.d.ts:1236:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
1663+
// build/src/reference.d.ts:1244:8 - (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
1664+
// build/src/reference.d.ts:1246:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
1665+
// build/src/reference.d.ts:1246:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}'
1666+
// build/src/reference.d.ts:1248:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
1667+
// build/src/reference.d.ts:1248:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}'
1668+
// build/src/reference.d.ts:1250:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
1669+
// build/src/reference.d.ts:1252:24 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag
1670+
// build/src/reference.d.ts:1252:17 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@"
1671+
// build/src/reference.d.ts:1261:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
1672+
// build/src/reference.d.ts:1263:8 - (tsdoc-undefined-tag) The TSDoc tag "@return" is not defined in this configuration
1673+
// build/src/reference.d.ts:1265:8 - (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
1674+
// build/src/reference.d.ts:1449:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
1675+
// build/src/reference.d.ts:1450:8 - (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
1676+
// build/src/reference.d.ts:1715:8 - (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
1677+
// build/src/reference.d.ts:1825:8 - (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
1678+
// build/src/reference.d.ts:1830:8 - (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
15911679
// build/src/serializer.d.ts:26:4 - (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
15921680
// build/src/serializer.d.ts:36:4 - (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration
15931681
// build/src/transaction.d.ts:239:8 - (tsdoc-undefined-tag) The TSDoc tag "@private" is not defined in this configuration

dev/src/aggregate.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/*!
1+
/**
22
* Copyright 2023 Google LLC. All Rights Reserved.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");

dev/src/convert.ts

Lines changed: 62 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {ApiMapValue, ProtobufJsValue} from './types';
2020
import {validateObject} from './validate';
2121

2222
import api = google.firestore.v1;
23+
import {RESERVED_MAP_KEY, RESERVED_MAP_KEY_VECTOR_VALUE} from './map-type';
2324

2425
/*!
2526
* @module firestore/convert
@@ -112,53 +113,72 @@ function bytesFromJson(bytesValue: string | Uint8Array): Uint8Array {
112113
* @return The string value for 'valueType'.
113114
*/
114115
export function detectValueType(proto: ProtobufJsValue): string {
116+
let valueType: string | undefined;
117+
115118
if (proto.valueType) {
116-
return proto.valueType;
117-
}
119+
valueType = proto.valueType;
120+
} else {
121+
const detectedValues: string[] = [];
118122

119-
const detectedValues: string[] = [];
123+
if (proto.stringValue !== undefined) {
124+
detectedValues.push('stringValue');
125+
}
126+
if (proto.booleanValue !== undefined) {
127+
detectedValues.push('booleanValue');
128+
}
129+
if (proto.integerValue !== undefined) {
130+
detectedValues.push('integerValue');
131+
}
132+
if (proto.doubleValue !== undefined) {
133+
detectedValues.push('doubleValue');
134+
}
135+
if (proto.timestampValue !== undefined) {
136+
detectedValues.push('timestampValue');
137+
}
138+
if (proto.referenceValue !== undefined) {
139+
detectedValues.push('referenceValue');
140+
}
141+
if (proto.arrayValue !== undefined) {
142+
detectedValues.push('arrayValue');
143+
}
144+
if (proto.nullValue !== undefined) {
145+
detectedValues.push('nullValue');
146+
}
147+
if (proto.mapValue !== undefined) {
148+
detectedValues.push('mapValue');
149+
}
150+
if (proto.geoPointValue !== undefined) {
151+
detectedValues.push('geoPointValue');
152+
}
153+
if (proto.bytesValue !== undefined) {
154+
detectedValues.push('bytesValue');
155+
}
120156

121-
if (proto.stringValue !== undefined) {
122-
detectedValues.push('stringValue');
123-
}
124-
if (proto.booleanValue !== undefined) {
125-
detectedValues.push('booleanValue');
126-
}
127-
if (proto.integerValue !== undefined) {
128-
detectedValues.push('integerValue');
129-
}
130-
if (proto.doubleValue !== undefined) {
131-
detectedValues.push('doubleValue');
132-
}
133-
if (proto.timestampValue !== undefined) {
134-
detectedValues.push('timestampValue');
135-
}
136-
if (proto.referenceValue !== undefined) {
137-
detectedValues.push('referenceValue');
138-
}
139-
if (proto.arrayValue !== undefined) {
140-
detectedValues.push('arrayValue');
141-
}
142-
if (proto.nullValue !== undefined) {
143-
detectedValues.push('nullValue');
144-
}
145-
if (proto.mapValue !== undefined) {
146-
detectedValues.push('mapValue');
147-
}
148-
if (proto.geoPointValue !== undefined) {
149-
detectedValues.push('geoPointValue');
150-
}
151-
if (proto.bytesValue !== undefined) {
152-
detectedValues.push('bytesValue');
157+
if (detectedValues.length !== 1) {
158+
throw new Error(
159+
`Unable to infer type value from '${JSON.stringify(proto)}'.`
160+
);
161+
}
162+
163+
valueType = detectedValues[0];
153164
}
154165

155-
if (detectedValues.length !== 1) {
156-
throw new Error(
157-
`Unable to infer type value from '${JSON.stringify(proto)}'.`
158-
);
166+
// Special handling of mapValues used to represent other data types
167+
if (valueType === 'mapValue') {
168+
const fields = proto.mapValue?.fields;
169+
if (fields) {
170+
const props = Object.keys(fields);
171+
if (
172+
props.indexOf(RESERVED_MAP_KEY) !== -1 &&
173+
detectValueType(fields[RESERVED_MAP_KEY]) === 'stringValue' &&
174+
fields[RESERVED_MAP_KEY].stringValue === RESERVED_MAP_KEY_VECTOR_VALUE
175+
) {
176+
valueType = 'vectorValue';
177+
}
178+
}
159179
}
160180

161-
return detectedValues[0];
181+
return valueType;
162182
}
163183

164184
/**
@@ -240,7 +260,8 @@ export function valueFromJson(fieldValue: api.IValue): api.IValue {
240260
},
241261
};
242262
}
243-
case 'mapValue': {
263+
case 'mapValue':
264+
case 'vectorValue': {
244265
const mapValue: ApiMapValue = {};
245266
const fields = fieldValue.mapValue!.fields;
246267
if (fields) {

0 commit comments

Comments
 (0)