Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Vector Search #2006

Merged
merged 70 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from 62 commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
36a50cb
Implement vector field type
wu-hui Sep 15, 2023
415c94e
Merge branch 'main' into wuandy/VectorType
wu-hui Sep 15, 2023
3551acb
test
wu-hui Sep 19, 2023
248af30
Merge branch 'main' into wuandy/VectorType
wu-hui Nov 27, 2023
6042c4d
Added extra logs and vector type test
wu-hui Nov 29, 2023
764800b
Add vector watch test
wu-hui Dec 5, 2023
93ae1d7
Add vectorvalue to dts.
wu-hui Jan 17, 2024
a3d57e3
get d.ts right.
wu-hui Jan 10, 2024
68cafe1
VectorQuery and QueryUtil setup
wu-hui Jan 10, 2024
f8f1ecb
Stage proto
wu-hui Jan 11, 2024
9f973a6
Actual serialization
wu-hui Jan 12, 2024
57a3f25
Update proto
wu-hui Jan 15, 2024
e15721d
More integration tests
wu-hui Jan 15, 2024
3898181
fix some tests. Also what to do with mismatch dimentions
wu-hui Jan 15, 2024
069a3e4
Add unit tests and minor fixes
wu-hui Jan 16, 2024
4b8b624
Add comments and delete stream()
wu-hui Jan 17, 2024
cff8b5b
Fix rebase.
wu-hui Jan 17, 2024
2f1b964
Address Mark's comments.
wu-hui Jan 23, 2024
9ebd42a
Merge branch 'main' into wuandy/VectorType
wu-hui Jan 23, 2024
1132ff3
get d.ts right.
wu-hui Jan 10, 2024
ddec250
VectorQuery and QueryUtil setup
wu-hui Jan 10, 2024
86ce16e
Stage proto
wu-hui Jan 11, 2024
df0b01a
Actual serialization
wu-hui Jan 12, 2024
1755a4e
Update proto
wu-hui Jan 15, 2024
8da86bc
More integration tests
wu-hui Jan 15, 2024
b8a043c
fix some tests. Also what to do with mismatch dimentions
wu-hui Jan 15, 2024
629ed38
Add unit tests and minor fixes
wu-hui Jan 16, 2024
5ca985f
Add comments and delete stream()
wu-hui Jan 17, 2024
66cab1f
Fix rebase.
wu-hui Jan 17, 2024
30f9977
Address comments
wu-hui Jan 23, 2024
2ae6cfb
Merge remote-tracking branch 'origin/wuandy/FindNearestImpl' into wua…
wu-hui Jan 23, 2024
a6af2da
Address comments
wu-hui Jan 23, 2024
1943803
No retry with cursor for vector for now.
wu-hui Jan 29, 2024
e535fd1
Fix error message test
wu-hui Jan 31, 2024
0af118f
Fix broken array equality
wu-hui Jan 31, 2024
41ab580
Implementing IndexTestHelper and updating findNearest tests to use th…
MarkDuckworth Feb 29, 2024
bcf7f45
Add dot product support.
MarkDuckworth Mar 4, 2024
625e8d7
Merge branch 'main' of github.com:googleapis/nodejs-firestore into ma…
MarkDuckworth Mar 4, 2024
b512348
Adding missing file
MarkDuckworth Mar 4, 2024
0a9ab60
Lint
MarkDuckworth Mar 4, 2024
6b52042
Updating API reference docs.
MarkDuckworth Mar 5, 2024
afc4f99
Fixing API reference docs for TSDoc output on CGC.
MarkDuckworth Mar 5, 2024
3d0267f
Fix API reference docs.
MarkDuckworth Mar 6, 2024
c3a337e
Supporting Vector field order onSnapshot.
MarkDuckworth Mar 11, 2024
f0c6228
Add missing map-type file.
MarkDuckworth Mar 11, 2024
8436c1e
Cleanup and linting.
MarkDuckworth Mar 11, 2024
2fcf70a
Supporting Proto3 JSON with vector.
MarkDuckworth Mar 12, 2024
adb01c1
Additional test for vector in a map.
MarkDuckworth Mar 13, 2024
d916197
Merge branch 'main' of github.com:googleapis/nodejs-firestore into ma…
MarkDuckworth Mar 14, 2024
d3254cd
Update deps.
MarkDuckworth Mar 14, 2024
f0ed9bc
Add DOT_PRODUCT to d.ts
MarkDuckworth Mar 14, 2024
4791b1b
Merge branch 'main' of github.com:googleapis/nodejs-firestore into ma…
MarkDuckworth Mar 15, 2024
f2986f8
Merge branch 'main' of github.com:googleapis/nodejs-firestore into ma…
MarkDuckworth Mar 15, 2024
3a9e2ab
Merge branch 'main' of github.com:googleapis/nodejs-firestore into ma…
MarkDuckworth Mar 15, 2024
0d1b967
Staging protos
MarkDuckworth Mar 15, 2024
9d598a1
Types update for admin protos.
MarkDuckworth Mar 15, 2024
4513c24
License header fixes.
MarkDuckworth Mar 19, 2024
35303af
Fix docs CI for jsdoc build.
MarkDuckworth Mar 19, 2024
a40366a
Updated api-report
MarkDuckworth Mar 21, 2024
6e3796d
More integration test cases.
MarkDuckworth Mar 21, 2024
e5a3d9c
Clarifying supported range on options.limit
MarkDuckworth Mar 21, 2024
3840563
Merge branch 'main' into markduckworth/findnearest
MarkDuckworth Mar 25, 2024
970a3f1
Revert changes from staging protos that were not applied in stable.
MarkDuckworth Mar 25, 2024
b98c3e8
Improving test comments/name for PR feedback.
MarkDuckworth Mar 25, 2024
563ef55
Merge Query Profile to Find Nearest
MarkDuckworth Mar 26, 2024
ee3f1d6
Merge branch 'main' of github.com:googleapis/nodejs-firestore into ma…
MarkDuckworth Mar 27, 2024
ccabafd
Revert rename of internal toProto method name. It is marked internal,…
MarkDuckworth Mar 27, 2024
43a5cd1
Update api-report.md
MarkDuckworth Mar 27, 2024
a0f103e
Re-adding two internal methods to the Query class to minimize the ris…
MarkDuckworth Mar 27, 2024
bb56524
Merge branch 'main' of github.com:googleapis/nodejs-firestore into ma…
MarkDuckworth Mar 28, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 123 additions & 44 deletions api-report/firestore.api.md

Large diffs are not rendered by default.

13 changes: 8 additions & 5 deletions dev/protos/google/firestore/admin/v1/field.proto
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2022 Google LLC
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -49,8 +49,8 @@ message Field {
// When false, the `Field`'s index configuration is defined explicitly.
bool uses_ancestor_config = 2;

// Output only. Specifies the resource name of the `Field` from which this field's
// index configuration is set (when `uses_ancestor_config` is true),
// Output only. Specifies the resource name of the `Field` from which this
// field's index configuration is set (when `uses_ancestor_config` is true),
// or from which it *would* be set if this field had no index configuration
// (when `uses_ancestor_config` is false).
string ancestor_field = 3;
Expand All @@ -65,9 +65,12 @@ message Field {

// The TTL (time-to-live) configuration for documents that have this `Field`
// set.
//
// Storing a timestamp value into a TTL-enabled field will be treated as
// the document's absolute expiration time. Using any other data type or
// leaving the field absent will disable the TTL for the individual document.
// the document's absolute expiration time. Timestamp values in the past
// indicate that the document is eligible for immediate expiration. Using any
// other data type or leaving the field absent will disable expiration for the
// individual document.
message TtlConfig {
// The state of applying the TTL configuration to all documents.
enum State {
Expand Down
4 changes: 2 additions & 2 deletions dev/protos/google/firestore/admin/v1/firestore_admin.proto
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,7 @@ message ListBackupSchedulesResponse {

// The request for [FirestoreAdmin.DeleteBackupSchedules][].
message DeleteBackupScheduleRequest {
// Required. The name of backup schedule.
// Required. The name of the backup schedule.
//
// Format
// `projects/{project}/databases/{database}/backupSchedules/{backup_schedule}`
Expand Down Expand Up @@ -862,4 +862,4 @@ message RestoreDatabaseRequest {
type: "firestore.googleapis.com/Backup"
}
];
}
}
2 changes: 1 addition & 1 deletion dev/protos/google/firestore/admin/v1/schedule.proto
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ message BackupSchedule {
}
}

// Represent a recurring schedule that runs at a specific time every day.
// Represents a recurring schedule that runs at a specific time every day.
//
// The time zone is UTC.
message DailyRecurrence {}
Expand Down
40 changes: 23 additions & 17 deletions dev/protos/google/longrunning/operations.proto
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ package google.longrunning;
import "google/api/annotations.proto";
import "google/api/client.proto";
import "google/protobuf/any.proto";
import "google/protobuf/descriptor.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/empty.proto";
import "google/rpc/status.proto";
import "google/protobuf/descriptor.proto";

option cc_enable_arenas = true;
option csharp_namespace = "Google.LongRunning";
Expand All @@ -45,12 +45,12 @@ extend google.protobuf.MethodOptions {
// Manages long-running operations with an API service.
//
// When an API method normally takes long time to complete, it can be designed
// to return [Operation][google.longrunning.Operation] to the client, and the client can use this
// interface to receive the real response asynchronously by polling the
// operation resource, or pass the operation resource to another API (such as
// Google Cloud Pub/Sub API) to receive the response. Any API service that
// returns long-running operations should implement the `Operations` interface
// so developers can have a consistent client experience.
// to return [Operation][google.longrunning.Operation] to the client, and the
// client can use this interface to receive the real response asynchronously by
// polling the operation resource, or pass the operation resource to another API
// (such as Google Cloud Pub/Sub API) to receive the response. Any API service
// that returns long-running operations should implement the `Operations`
// interface so developers can have a consistent client experience.
service Operations {
option (google.api.default_host) = "longrunning.googleapis.com";

Expand Down Expand Up @@ -100,8 +100,9 @@ service Operations {
// other methods to check whether the cancellation succeeded or whether the
// operation completed despite cancellation. On successful cancellation,
// the operation is not deleted; instead, it becomes an operation with
// an [Operation.error][google.longrunning.Operation.error] value with a [google.rpc.Status.code][google.rpc.Status.code] of 1,
// corresponding to `Code.CANCELLED`.
// an [Operation.error][google.longrunning.Operation.error] value with a
// [google.rpc.Status.code][google.rpc.Status.code] of 1, corresponding to
// `Code.CANCELLED`.
rpc CancelOperation(CancelOperationRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
post: "/v1/{name=operations/**}:cancel"
Expand All @@ -119,8 +120,7 @@ service Operations {
// Note that this method is on a best-effort basis. It may return the latest
// state before the specified timeout (including immediately), meaning even an
// immediate response is no guarantee that the operation is done.
rpc WaitOperation(WaitOperationRequest) returns (Operation) {
}
rpc WaitOperation(WaitOperationRequest) returns (Operation) {}
}

// This resource represents a long-running operation that is the result of a
Expand Down Expand Up @@ -161,13 +161,15 @@ message Operation {
}
}

// The request message for [Operations.GetOperation][google.longrunning.Operations.GetOperation].
// The request message for
// [Operations.GetOperation][google.longrunning.Operations.GetOperation].
message GetOperationRequest {
// The name of the operation resource.
string name = 1;
}

// The request message for [Operations.ListOperations][google.longrunning.Operations.ListOperations].
// The request message for
// [Operations.ListOperations][google.longrunning.Operations.ListOperations].
message ListOperationsRequest {
// The name of the operation's parent resource.
string name = 4;
Expand All @@ -182,7 +184,8 @@ message ListOperationsRequest {
string page_token = 3;
}

// The response message for [Operations.ListOperations][google.longrunning.Operations.ListOperations].
// The response message for
// [Operations.ListOperations][google.longrunning.Operations.ListOperations].
message ListOperationsResponse {
// A list of operations that matches the specified filter in the request.
repeated Operation operations = 1;
Expand All @@ -191,19 +194,22 @@ message ListOperationsResponse {
string next_page_token = 2;
}

// The request message for [Operations.CancelOperation][google.longrunning.Operations.CancelOperation].
// The request message for
// [Operations.CancelOperation][google.longrunning.Operations.CancelOperation].
message CancelOperationRequest {
// The name of the operation resource to be cancelled.
string name = 1;
}

// The request message for [Operations.DeleteOperation][google.longrunning.Operations.DeleteOperation].
// The request message for
// [Operations.DeleteOperation][google.longrunning.Operations.DeleteOperation].
message DeleteOperationRequest {
// The name of the operation resource to be deleted.
string name = 1;
}

// The request message for [Operations.WaitOperation][google.longrunning.Operations.WaitOperation].
// The request message for
// [Operations.WaitOperation][google.longrunning.Operations.WaitOperation].
message WaitOperationRequest {
// The name of the operation resource to wait on.
string name = 1;
Expand Down
8 changes: 3 additions & 5 deletions dev/protos/google/rpc/status.proto
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2022 Google LLC
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -33,14 +33,12 @@ option objc_class_prefix = "RPC";
// You can find out more about this error model and how to work with it in the
// [API Design Guide](https://cloud.google.com/apis/design/errors).
message Status {
// The status code, which should be an enum value of
// [google.rpc.Code][google.rpc.Code].
// The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code].
int32 code = 1;

// A developer-facing error message, which should be in English. Any
// user-facing error message should be localized and sent in the
// [google.rpc.Status.details][google.rpc.Status.details] field, or localized
// by the client.
// [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client.
string message = 2;

// A list of messages that carry the error details. There is a common set of
Expand Down
2 changes: 1 addition & 1 deletion dev/src/collection-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export class CollectionGroup<
// Partition queries require explicit ordering by __name__.
const queryWithDefaultOrder = this.orderBy(FieldPath.documentId());
const request: api.IPartitionQueryRequest =
queryWithDefaultOrder.toProto();
queryWithDefaultOrder._toProto();

// Since we are always returning an extra partition (with an empty endBefore
// cursor), we reduce the desired partition count by one.
Expand Down
103 changes: 62 additions & 41 deletions dev/src/convert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {ApiMapValue, ProtobufJsValue} from './types';
import {validateObject} from './validate';

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

/*!
* @module firestore/convert
Expand Down Expand Up @@ -112,53 +113,72 @@ function bytesFromJson(bytesValue: string | Uint8Array): Uint8Array {
* @return The string value for 'valueType'.
*/
export function detectValueType(proto: ProtobufJsValue): string {
let valueType: string | undefined;

if (proto.valueType) {
return proto.valueType;
}
valueType = proto.valueType;
} else {
const detectedValues: string[] = [];

const detectedValues: string[] = [];
if (proto.stringValue !== undefined) {
detectedValues.push('stringValue');
}
if (proto.booleanValue !== undefined) {
detectedValues.push('booleanValue');
}
if (proto.integerValue !== undefined) {
detectedValues.push('integerValue');
}
if (proto.doubleValue !== undefined) {
detectedValues.push('doubleValue');
}
if (proto.timestampValue !== undefined) {
detectedValues.push('timestampValue');
}
if (proto.referenceValue !== undefined) {
detectedValues.push('referenceValue');
}
if (proto.arrayValue !== undefined) {
detectedValues.push('arrayValue');
}
if (proto.nullValue !== undefined) {
detectedValues.push('nullValue');
}
if (proto.mapValue !== undefined) {
detectedValues.push('mapValue');
}
if (proto.geoPointValue !== undefined) {
detectedValues.push('geoPointValue');
}
if (proto.bytesValue !== undefined) {
detectedValues.push('bytesValue');
}

if (proto.stringValue !== undefined) {
detectedValues.push('stringValue');
}
if (proto.booleanValue !== undefined) {
detectedValues.push('booleanValue');
}
if (proto.integerValue !== undefined) {
detectedValues.push('integerValue');
}
if (proto.doubleValue !== undefined) {
detectedValues.push('doubleValue');
}
if (proto.timestampValue !== undefined) {
detectedValues.push('timestampValue');
}
if (proto.referenceValue !== undefined) {
detectedValues.push('referenceValue');
}
if (proto.arrayValue !== undefined) {
detectedValues.push('arrayValue');
}
if (proto.nullValue !== undefined) {
detectedValues.push('nullValue');
}
if (proto.mapValue !== undefined) {
detectedValues.push('mapValue');
}
if (proto.geoPointValue !== undefined) {
detectedValues.push('geoPointValue');
}
if (proto.bytesValue !== undefined) {
detectedValues.push('bytesValue');
if (detectedValues.length !== 1) {
throw new Error(
`Unable to infer type value from '${JSON.stringify(proto)}'.`
);
}

valueType = detectedValues[0];
}

if (detectedValues.length !== 1) {
throw new Error(
`Unable to infer type value from '${JSON.stringify(proto)}'.`
);
// Special handling of mapValues used to represent other data types
if (valueType === 'mapValue') {
const fields = proto.mapValue?.fields;
if (fields) {
const props = Object.keys(fields);
if (
props.indexOf(RESERVED_MAP_KEY) !== -1 &&
detectValueType(fields[RESERVED_MAP_KEY]) === 'stringValue' &&
fields[RESERVED_MAP_KEY].stringValue === RESERVED_MAP_KEY_VECTOR_VALUE
) {
valueType = 'vectorValue';
}
}
}

return detectedValues[0];
return valueType;
}

/**
Expand Down Expand Up @@ -199,7 +219,8 @@ export function valueFromJson(fieldValue: api.IValue): api.IValue {
},
};
}
case 'mapValue': {
case 'mapValue':
case 'vectorValue': {
const mapValue: ApiMapValue = {};
const fields = fieldValue.mapValue!.fields;
if (fields) {
Expand Down
Loading
Loading