Skip to content

Commit 18f09ef

Browse files
authored
Merge pull request #484 from M4xymm/RDBC-918
RDBC-918 - Allow to query vector searching using a document id
2 parents 2bbd111 + 64cbfc4 commit 18f09ef

File tree

12 files changed

+377
-191
lines changed

12 files changed

+377
-191
lines changed

src/Documents/Queries/VectorSearch/Common/VectorFieldBase.ts

Lines changed: 0 additions & 64 deletions
This file was deleted.
Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
import { IVectorEmbeddingField, IVectorEmbeddingFieldFactoryAccessor } from "../../../Session/IVectorFieldFactory.js";
2-
import { VectorFieldBase } from "../Common/VectorFieldBase.js";
1+
import { IVectorEmbeddingField, IVectorEmbeddingFieldFactoryAccessor } from "../../../Session/VectorFieldFactory.js";
32
import {VectorEmbeddingType} from "../VectorEmbeddingType.js";
43
import { Field } from "../../../../Types/index.js";
54

6-
export class VectorEmbeddingField<T> extends VectorFieldBase<T> implements
5+
export class VectorEmbeddingField<T> implements
76
IVectorEmbeddingField,
87
IVectorEmbeddingFieldFactoryAccessor<T> {
9-
8+
public fieldName: string;
109
public sourceQuantizationType: VectorEmbeddingType;
1110
public destinationQuantizationType: VectorEmbeddingType;
1211
public isBase64Encoded: boolean;
@@ -15,20 +14,12 @@ export class VectorEmbeddingField<T> extends VectorFieldBase<T> implements
1514
constructor(fieldName: Field<T>,
1615
sourceQuantizationType: VectorEmbeddingType = "Single",
1716
isBase64Encoded: boolean = false) {
18-
super(fieldName);
17+
this.fieldName = fieldName;
1918
this.sourceQuantizationType = sourceQuantizationType;
2019
this.destinationQuantizationType = sourceQuantizationType;
2120
this.isBase64Encoded = isBase64Encoded;
22-
this.updateFieldName();
2321
}
2422

25-
private updateFieldName(): void {
26-
this.fieldName = this.getFormattedFieldName(
27-
this.rawFieldName,
28-
this.sourceQuantizationType,
29-
this.destinationQuantizationType
30-
);
31-
}
3223

3324
public targetQuantization(targetEmbeddingQuantization: VectorEmbeddingType): IVectorEmbeddingField {
3425
if (targetEmbeddingQuantization === "Text") {
@@ -43,7 +34,6 @@ export class VectorEmbeddingField<T> extends VectorFieldBase<T> implements
4334
throw new Error(`Cannot quantize already quantized embeddings. Source VectorEmbeddingType is ${this.sourceQuantizationType}; however the destination is ${this.destinationQuantizationType}.`);
4435
}
4536

46-
this.updateFieldName();
4737
return this;
4838
}
4939
}
Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,31 @@
1-
import { IVectorEmbeddingFieldFactoryAccessor, IVectorEmbeddingTextField } from "../../../Session/IVectorFieldFactory.js";
2-
import { VectorFieldBase } from "../Common/VectorFieldBase.js";
3-
import {VectorEmbeddingType} from "../VectorEmbeddingType.js";
1+
import {
2+
IVectorEmbeddingFieldFactoryAccessor,
3+
IVectorEmbeddingTextField
4+
} from "../../../Session/VectorFieldFactory.js";
5+
import { VectorEmbeddingType } from "../VectorEmbeddingType.js";
46
import { Field } from "../../../../Types/index.js";
57

6-
export class VectorEmbeddingTextField<T> extends VectorFieldBase<T> implements
8+
export class VectorEmbeddingTextField<T> implements
79
IVectorEmbeddingTextField,
810
IVectorEmbeddingFieldFactoryAccessor<T> {
911

12+
public fieldName: string;
1013
public sourceQuantizationType: VectorEmbeddingType = "Text";
1114
public destinationQuantizationType: VectorEmbeddingType = "Single";
1215
public isBase64Encoded: boolean = false;
1316
public embeddingsGenerationTaskIdentifier: string = "";
1417

1518
constructor(fieldName: Field<T>) {
16-
super(fieldName);
17-
this.updateFieldName();
19+
this.fieldName = fieldName;
1820
}
1921

20-
private updateFieldName(): void {
21-
this.fieldName = this.getFormattedFieldName(
22-
this.rawFieldName,
23-
this.sourceQuantizationType,
24-
this.destinationQuantizationType,
25-
this.embeddingsGenerationTaskIdentifier
26-
);
27-
}
2822

2923
public targetQuantization(targetEmbeddingQuantization: VectorEmbeddingType): IVectorEmbeddingTextField {
3024
if (targetEmbeddingQuantization === "Text") {
3125
throw new Error("Cannot quantize the embedding to Text. This option is only available for sourceQuantizationType.");
3226
}
3327

3428
this.destinationQuantizationType = targetEmbeddingQuantization;
35-
this.updateFieldName();
3629
return this;
3730
}
3831

@@ -42,7 +35,6 @@ export class VectorEmbeddingTextField<T> extends VectorFieldBase<T> implements
4235
}
4336

4437
this.embeddingsGenerationTaskIdentifier = embeddingsGenerationTaskIdentifier;
45-
this.updateFieldName();
4638
return this;
4739
}
4840
}
Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
import { IVectorField } from "../../../Session/IVectorFieldFactory.js";
2-
import { VectorFieldBase } from "../Common/VectorFieldBase.js";
1+
import { IVectorField } from "../../../Session/VectorFieldFactory.js";
32
import { Field } from "../../../../Types/index.js";
43

5-
export class VectorField<T> extends VectorFieldBase<T> implements IVectorField {
4+
export class VectorField<T> implements IVectorField {
5+
public fieldName: string;
6+
67
constructor(fieldName: Field<T>) {
7-
super(fieldName);
8-
this._byFieldMethodUsed = true;
98
this.fieldName = fieldName;
109
}
1110
}

src/Documents/Queries/VectorSearch/VectorEmbeddingFieldFactory.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {
33
IVectorEmbeddingTextField,
44
IVectorField,
55
IVectorFieldFactory
6-
} from "../../Session/IVectorFieldFactory.js";
6+
} from "../../Session/VectorFieldFactory.js";
77
import { VectorField } from "./Fields/VectorField.js";
88
import { VectorEmbeddingField } from "./Fields/VectorEmbeddingField.js";
99
import { VectorEmbeddingTextField } from "./Fields/VectorEmbeddingTextField.js";

src/Documents/Session/AbstractDocumentQuery.ts

Lines changed: 45 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,11 @@ import {
9494
IVectorEmbeddingFieldFactoryAccessor, IVectorEmbeddingTextField,
9595
IVectorField,
9696
IVectorFieldFactory, IVectorFieldValueFactory, VectorEmbeddingFieldValueFactory
97-
} from "./IVectorFieldFactory.js";
97+
} from "./VectorFieldFactory.js";
9898
import { VectorEmbeddingFieldFactory } from "../Queries/VectorSearch/VectorEmbeddingFieldFactory.js";
9999
import { Field } from "../../Types/index.js";
100100
import { JsonSerializer } from "../../Mapping/Json/Serializer.js";
101+
import { VectorSearchToken } from "./Tokens/VectorSearchToken.js";
101102

102103
/**
103104
* A query against a Raven index
@@ -2577,56 +2578,63 @@ export abstract class AbstractDocumentQuery<T extends object, TSelf extends Abst
25772578
) {
25782579
this._assertMethodIsCurrentlySupported("vectorSearch");
25792580

2581+
const fieldAccessor = this._resolveVectorSearchFieldAccessor(fieldName);
2582+
const {value, isDocumentId} = this._resolveVectorSearchValueFactory(valueOrFactory);
2583+
2584+
const tokens = this._getCurrentWhereTokens();
2585+
this._appendOperatorIfNeeded(tokens);
2586+
this._negateIfNeeded(tokens, fieldAccessor.fieldName);
2587+
2588+
const sourceQuantizationType = VectorSearchToken.getSourceQuantizationType(fieldAccessor);
2589+
const targetQuantizationType = VectorSearchToken.getTargetQuantizationType(fieldAccessor);
2590+
const taskIdentifier = VectorSearchToken.getTaskIdentifier(fieldAccessor);
2591+
2592+
const parameterName = this._addQueryParameter(value);
2593+
2594+
const vectorSearchToken = new VectorSearchToken(
2595+
fieldAccessor.fieldName,
2596+
parameterName,
2597+
sourceQuantizationType,
2598+
targetQuantizationType,
2599+
options?.similarity || null,
2600+
options?.numberOfCandidates || null,
2601+
options?.isExact || VectorSearchToken.DEFAULT_IS_EXACT,
2602+
isDocumentId,
2603+
taskIdentifier
2604+
);
2605+
2606+
tokens.push(vectorSearchToken);
2607+
}
2608+
2609+
2610+
private _resolveVectorSearchFieldAccessor(fieldName: Field<T> | ((factory: IVectorFieldFactory<T>) => IVectorField | IVectorEmbeddingField | IVectorEmbeddingTextField)): IVectorEmbeddingFieldFactoryAccessor<T> {
25802611
const vectorFactory = new VectorEmbeddingFieldFactory<T>();
2581-
let fieldAccessor: IVectorEmbeddingFieldFactoryAccessor<T>;
2582-
2612+
25832613
if (typeof fieldName === "string") {
2584-
fieldAccessor = vectorFactory.withField(fieldName) as IVectorEmbeddingFieldFactoryAccessor<T>;
2614+
return vectorFactory.withField(fieldName) as IVectorEmbeddingFieldFactoryAccessor<T>;
25852615
} else if (typeof fieldName === "function") {
2586-
fieldAccessor = fieldName(vectorFactory) as IVectorEmbeddingFieldFactoryAccessor<T>;
2616+
return fieldName(vectorFactory) as IVectorEmbeddingFieldFactoryAccessor<T>;
25872617
} else {
2588-
throwError("InvalidArgumentException",
2589-
"fieldName must be either a string or a function that selects a vector field");
2618+
throwError("InvalidArgumentException", "fieldName must be either a string or a function that selects a vector field");
25902619
}
2591-
2592-
const whereParams = new WhereParams();
2593-
whereParams.fieldName = fieldAccessor.fieldName;
2620+
}
25942621

2595-
// Handle value or valueFactory
2622+
private _resolveVectorSearchValueFactory(valueOrFactory: number[] | string | ((factory: IVectorFieldValueFactory) => void)) {
25962623
if (typeof valueOrFactory === "function") {
25972624
const fieldValueFactory = new VectorEmbeddingFieldValueFactory();
25982625
valueOrFactory(fieldValueFactory);
25992626

2600-
if (fieldValueFactory.embeddings) {
2601-
whereParams.value = fieldValueFactory.embeddings;
2602-
} else if (fieldValueFactory.embedding) {
2603-
whereParams.value = fieldValueFactory.embedding;
2604-
} else if (fieldValueFactory.text) {
2605-
whereParams.value = fieldValueFactory.text;
2606-
} else if (fieldValueFactory.texts) {
2607-
whereParams.value = fieldValueFactory.texts;
2608-
} else {
2627+
const value = fieldValueFactory.embedding || fieldValueFactory.embeddings ||
2628+
fieldValueFactory.text || fieldValueFactory.texts || fieldValueFactory.byId;
2629+
2630+
if (!value) {
26092631
throwError("InvalidOperationException", "No value was provided in the valueFactory");
26102632
}
2633+
2634+
return {value, isDocumentId: !!fieldValueFactory.byId};
26112635
} else {
2612-
whereParams.value = valueOrFactory;
2636+
return {value: valueOrFactory, isDocumentId: false};
26132637
}
2614-
2615-
whereParams.allowWildcards = true;
2616-
const transformToEqualValue = this._transformValue(whereParams);
2617-
2618-
const tokens = this._getCurrentWhereTokens();
2619-
this._appendOperatorIfNeeded(tokens);
2620-
this._negateIfNeeded(tokens, whereParams.fieldName);
2621-
2622-
const whereToken = WhereToken.create(
2623-
"VectorSearch",
2624-
whereParams.fieldName,
2625-
this._addQueryParameter(transformToEqualValue),
2626-
new WhereOptions({vectorSearch: options, exact: options?.isExact})
2627-
);
2628-
2629-
tokens.push(whereToken);
26302638
}
26312639
}
26322640

src/Documents/Session/DocumentQuery.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ import {
6464
IVectorField,
6565
IVectorFieldFactory,
6666
IVectorFieldValueFactory
67-
} from "./IVectorFieldFactory.js";
67+
} from "./VectorFieldFactory.js";
6868

6969
export const NESTED_OBJECT_TYPES_PROJECTION_FIELD = "__PROJECTED_NESTED_OBJECT_TYPES__";
7070

src/Documents/Session/IDocumentQuery.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import {
2727
IVectorEmbeddingTextField,
2828
IVectorField,
2929
IVectorFieldFactory, IVectorFieldValueFactory
30-
} from "./IVectorFieldFactory.js";
30+
} from "./VectorFieldFactory.js";
3131

3232
/**
3333
* A query against a Raven index

0 commit comments

Comments
 (0)