Skip to content

Commit 64d2a2b

Browse files
authored
Merge pull request #299 from weaviate/feat/add-vector
Support adding named vectors to a collection with existing named vectors.
2 parents c26380a + 40d7841 commit 64d2a2b

File tree

8 files changed

+247
-97
lines changed

8 files changed

+247
-97
lines changed

.github/workflows/main.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ env:
1414
WEAVIATE_128: 1.28.11
1515
WEAVIATE_129: 1.29.1
1616
WEAVIATE_130: 1.30.1
17+
WEAVIATE_131: 1.31.0
1718

1819
concurrency:
1920
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}

src/collections/config/index.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ import { WeaviateShardStatus } from '../../openapi/types.js';
44
import ClassUpdater from '../../schema/classUpdater.js';
55
import { ClassGetter, PropertyCreator, ShardUpdater } from '../../schema/index.js';
66
import ShardsGetter from '../../schema/shardsGetter.js';
7+
import VectorAdder from '../../schema/vectorAdder.js';
78
import { DbVersionSupport } from '../../utils/dbVersion.js';
89
import {
910
PropertyConfigCreate,
1011
ReferenceMultiTargetConfigCreate,
1112
ReferenceSingleTargetConfigCreate,
13+
VectorizersConfigAdd,
1214
} from '../configure/types/index.js';
1315
import { MergeWithExisting } from './classes.js';
1416
import {
@@ -23,7 +25,7 @@ import {
2325
VectorIndexConfigFlat,
2426
VectorIndexConfigHNSW,
2527
} from './types/index.js';
26-
import { classToCollection, resolveProperty, resolveReference } from './utils.js';
28+
import { classToCollection, makeVectorsConfig, resolveProperty, resolveReference } from './utils.js';
2729

2830
const config = <T>(
2931
connection: Connection,
@@ -47,6 +49,11 @@ const config = <T>(
4749
.withProperty(resolveReference<any>(reference))
4850
.do()
4951
.then(() => {}),
52+
addVector: async (vectors: VectorizersConfigAdd<T>) => {
53+
const supportsDynamicVectorIndex = await dbVersionSupport.supportsDynamicVectorIndex();
54+
const { vectorsConfig } = makeVectorsConfig(vectors, supportsDynamicVectorIndex);
55+
return new VectorAdder(connection).withClassName(name).withVectors(vectorsConfig).do();
56+
},
5057
get: () => getRaw().then(classToCollection<T>),
5158
getShards: () => {
5259
let builder = new ShardsGetter(connection).withClassName(name);
@@ -114,6 +121,17 @@ export interface Config<T> {
114121
addReference: (
115122
reference: ReferenceSingleTargetConfigCreate<T> | ReferenceMultiTargetConfigCreate<T>
116123
) => Promise<void>;
124+
/**
125+
* Add one or more named vectors to the collection in Weaviate.
126+
* Named vectors can be added to collections with existing named vectors only.
127+
*
128+
* Existing named vectors are immutable in Weaviate. The client will not include
129+
* any of those in the request.
130+
*
131+
* @param {VectorizersConfigAdd<any>} vectors Vector configurations.
132+
* @returns {Promise<void>} A promise that resolves when the named vector has been created.
133+
*/
134+
addVector: (vectors: VectorizersConfigAdd<T>) => Promise<void>;
117135
/**
118136
* Get the configuration for this collection from Weaviate.
119137
*

src/collections/config/integration.test.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/* eslint-disable @typescript-eslint/no-non-null-assertion */
2+
import { requireAtLeast } from '../../../test/version.js';
23
import { WeaviateUnsupportedFeatureError } from '../../errors.js';
34
import weaviate, { WeaviateClient, weaviateV2 } from '../../index.js';
45
import {
@@ -386,6 +387,43 @@ describe('Testing of the collection.config namespace', () => {
386387
]);
387388
});
388389

390+
requireAtLeast(
391+
1,
392+
31,
393+
0
394+
)('Mutable named vectors', () => {
395+
it('should be able to add named vectors to a collection', async () => {
396+
const collectionName = 'TestCollectionConfigAddVector' as const;
397+
const collection = await client.collections.create({
398+
name: collectionName,
399+
vectorizers: weaviate.configure.vectorizer.none(),
400+
});
401+
// Add a single named vector
402+
await collection.config.addVector(weaviate.configure.vectorizer.none({ name: 'vector-a' }));
403+
404+
// Add several named vectors
405+
await collection.config.addVector([
406+
weaviate.configure.vectorizer.none({ name: 'vector-b' }),
407+
weaviate.configure.vectorizer.none({ name: 'vector-c' }),
408+
]);
409+
410+
// Trying to update 'default' vector -- should be omitted from request.
411+
await collection.config.addVector(
412+
weaviate.configure.vectorizer.none({
413+
name: 'default',
414+
vectorIndexConfig: weaviate.configure.vectorIndex.flat(),
415+
})
416+
);
417+
418+
const config = await collection.config.get();
419+
expect(config.vectorizers).toHaveProperty('vector-a');
420+
expect(config.vectorizers).toHaveProperty('vector-b');
421+
expect(config.vectorizers).toHaveProperty('vector-c');
422+
423+
expect(config.vectorizers.default).toHaveProperty('indexType', 'hnsw');
424+
});
425+
});
426+
389427
it('should get the shards of a sharded collection', async () => {
390428
const shards = await client.collections
391429
.create({

src/collections/config/utils.ts

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1-
import { WeaviateDeserializationError } from '../../errors.js';
21
import {
2+
WeaviateDeserializationError,
3+
WeaviateInvalidInputError,
4+
WeaviateUnsupportedFeatureError,
5+
} from '../../errors.js';
6+
import {
7+
Properties,
38
WeaviateBM25Config,
49
WeaviateClass,
510
WeaviateInvertedIndexConfig,
@@ -13,11 +18,19 @@ import {
1318
WeaviateVectorIndexConfig,
1419
WeaviateVectorsConfig,
1520
} from '../../openapi/types.js';
21+
import { DbVersionSupport } from '../../utils/dbVersion.js';
22+
import { QuantizerGuards } from '../configure/parsing.js';
1623
import {
1724
PropertyConfigCreate,
1825
ReferenceConfigCreate,
1926
ReferenceMultiTargetConfigCreate,
2027
ReferenceSingleTargetConfigCreate,
28+
VectorIndexConfigCreate,
29+
VectorIndexConfigDynamicCreate,
30+
VectorIndexConfigFlatCreate,
31+
VectorIndexConfigHNSWCreate,
32+
VectorizersConfigAdd,
33+
VectorizersConfigCreate,
2134
} from '../configure/types/index.js';
2235
import {
2336
BQConfig,
@@ -46,6 +59,7 @@ import {
4659
VectorIndexConfigHNSW,
4760
VectorIndexConfigType,
4861
VectorIndexFilterStrategy,
62+
VectorIndexType,
4963
VectorizerConfig,
5064
} from './types/index.js';
5165

@@ -123,6 +137,91 @@ export const classToCollection = <T>(cls: WeaviateClass): CollectionConfig => {
123137
};
124138
};
125139

140+
export const parseVectorIndex = (module: ModuleConfig<VectorIndexType, VectorIndexConfigCreate>): any => {
141+
if (module.config === undefined) return undefined;
142+
if (module.name === 'dynamic') {
143+
const { hnsw, flat, ...conf } = module.config as VectorIndexConfigDynamicCreate;
144+
return {
145+
...conf,
146+
hnsw: parseVectorIndex({ name: 'hnsw', config: hnsw }),
147+
flat: parseVectorIndex({ name: 'flat', config: flat }),
148+
};
149+
}
150+
const { quantizer, ...conf } = module.config as
151+
| VectorIndexConfigFlatCreate
152+
| VectorIndexConfigHNSWCreate
153+
| Record<string, any>;
154+
if (quantizer === undefined) return conf;
155+
if (QuantizerGuards.isBQCreate(quantizer)) {
156+
const { type, ...quant } = quantizer;
157+
return {
158+
...conf,
159+
bq: {
160+
...quant,
161+
enabled: true,
162+
},
163+
};
164+
}
165+
if (QuantizerGuards.isPQCreate(quantizer)) {
166+
const { type, ...quant } = quantizer;
167+
return {
168+
...conf,
169+
pq: {
170+
...quant,
171+
enabled: true,
172+
},
173+
};
174+
}
175+
};
176+
177+
export const parseVectorizerConfig = (config?: VectorizerConfig): any => {
178+
if (config === undefined) return {};
179+
const { vectorizeCollectionName, ...rest } = config as any;
180+
return {
181+
...rest,
182+
vectorizeClassName: vectorizeCollectionName,
183+
};
184+
};
185+
186+
export const makeVectorsConfig = <TProperties extends Properties | undefined = undefined>(
187+
configVectorizers: VectorizersConfigCreate<TProperties> | VectorizersConfigAdd<TProperties>,
188+
supportsDynamicVectorIndex: Awaited<ReturnType<DbVersionSupport['supportsDynamicVectorIndex']>>
189+
) => {
190+
let vectorizers: string[] = [];
191+
const vectorsConfig: Record<string, any> = {};
192+
const vectorizersConfig = Array.isArray(configVectorizers)
193+
? configVectorizers
194+
: [
195+
{
196+
...configVectorizers,
197+
name: configVectorizers.name || 'default',
198+
},
199+
];
200+
vectorizersConfig.forEach((v) => {
201+
if (v.vectorIndex.name === 'dynamic' && !supportsDynamicVectorIndex.supports) {
202+
throw new WeaviateUnsupportedFeatureError(supportsDynamicVectorIndex.message);
203+
}
204+
const vectorConfig: any = {
205+
vectorIndexConfig: parseVectorIndex(v.vectorIndex),
206+
vectorIndexType: v.vectorIndex.name,
207+
vectorizer: {},
208+
};
209+
const vectorizer = v.vectorizer.name === 'text2vec-azure-openai' ? 'text2vec-openai' : v.vectorizer.name;
210+
vectorizers = [...vectorizers, vectorizer];
211+
vectorConfig.vectorizer[vectorizer] = {
212+
properties: v.properties,
213+
...parseVectorizerConfig(v.vectorizer.config),
214+
};
215+
if (v.name === undefined) {
216+
throw new WeaviateInvalidInputError(
217+
'vectorName is required for each vectorizer when specifying more than one vectorizer'
218+
);
219+
}
220+
vectorsConfig[v.name] = vectorConfig;
221+
});
222+
return { vectorsConfig, vectorizers };
223+
};
224+
126225
function populated<T>(v: T | null | undefined): v is T {
127226
return v !== undefined && v !== null;
128227
}

src/collections/configure/types/vectorizer.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,11 @@ export type VectorConfigUpdate<N extends string | undefined, I extends VectorInd
5555
};
5656

5757
export type VectorizersConfigCreate<T> =
58-
| VectorConfigCreate<PrimitiveKeys<T>, undefined, VectorIndexType, Vectorizer>
58+
| VectorConfigCreate<PrimitiveKeys<T>, string | undefined, VectorIndexType, Vectorizer>
59+
| VectorConfigCreate<PrimitiveKeys<T>, string, VectorIndexType, Vectorizer>[];
60+
61+
export type VectorizersConfigAdd<T> =
62+
| VectorConfigCreate<PrimitiveKeys<T>, string, VectorIndexType, Vectorizer>
5963
| VectorConfigCreate<PrimitiveKeys<T>, string, VectorIndexType, Vectorizer>[];
6064

6165
export type ConfigureNonTextVectorizerOptions<

0 commit comments

Comments
 (0)