Skip to content

Commit

Permalink
[2.4] add alterCollectionFieldProperties API (#393)
Browse files Browse the repository at this point in the history
* finish alter collection field properties

Signed-off-by: ryjiang <[email protected]>

* fix test

Signed-off-by: ryjiang <[email protected]>

---------

Signed-off-by: ryjiang <[email protected]>
  • Loading branch information
shanghaikid authored Dec 23, 2024
1 parent f593f90 commit 889fe0c
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 38 deletions.
46 changes: 46 additions & 0 deletions milvus/grpc/Collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import {
CreateCollectionWithSchemaReq,
FieldSchema,
DropCollectionPropertiesReq,
AlterCollectionFieldPropertiesReq,
isVectorType,
} from '../';

Expand Down Expand Up @@ -331,6 +332,51 @@ export class Collection extends Database {
*/
alterCollection = this.alterCollectionProperties;

/**
* Modifies a collection field's properties.
* Note that this operation only modifies the properties of the field, not the field itself.
*
* @param {AlterCollectionFieldPropertiesReq} data - The request parameters.
* @param {string} data.collection_name - The name of the collection to modify.
* @param {string} data.field_name - The name of the field to modify.
* @param {Object} data.properties - The properties to modify. For example, to change field mmap setting and max_length, use { 'mmap.enabled', true, max_length: 128}.
* @param {string} [data.db_name] - The name of the database where the collection is located.
* @param {number} [data.timeout] - An optional duration of time in milliseconds to allow for the RPC. If it is set to undefined, the client keeps waiting until the server responds or error occurs. Default is undefined.
*
* @returns {Promise<ResStatus>} The response status of the operation.
* @returns {string} status.error_code - The error code of the operation.
* @returns {string} status.reason - The reason for the error, if any.
*
* @example
* ```
* const milvusClient = new milvusClient(MILUVS_ADDRESS);
* const resStatus = await milvusClient.alterCollectionField({
* collection_name: 'my-collection',
* field_name: 'my-field',
* properties: {"mmap.enabled": true}
* });
* ```
*/
async alterCollectionFieldProperties(
data: AlterCollectionFieldPropertiesReq
): Promise<ResStatus> {
const req: any = {
collection_name: data.collection_name,
field_name: data.field_name,
properties: parseToKeyValue(data.properties),
};
if (data.db_name) {
req.db_name = data.db_name;
}
const promise = await promisify(
this.channelPool,
'AlterCollectionField',
req,
data?.timeout || this.timeout
);
return promise;
}

/**
* Drops collection properties.
* Note that this operation only deletes the properties of the collection, not the collection itself.
Expand Down
2 changes: 1 addition & 1 deletion milvus/grpc/Data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ export class Data extends Collection {
name: v.name,
type: v.data_type, // milvus return string here
elementType: v.element_type,
dim: Number(findKeyValue(v.type_params, 'dim')),
dim: Number(v.dim),
data: [], // values container
},
])
Expand Down
50 changes: 29 additions & 21 deletions milvus/types/Collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,6 @@ import {
ShowCollectionsType,
} from '../';

// returned from milvus
export interface FieldSchema {
type_params: KeyValuePair[];
index_params: KeyValuePair[];
fieldID: string | number;
name: string;
is_primary_key?: boolean;
description: string;
data_type: keyof typeof DataType;
autoID: boolean;
state: string;
element_type?: keyof typeof DataType;
default_value?: number | string;
dataType: DataType;
is_partition_key?: boolean;
is_dynamic?: boolean;
is_clustering_key?: boolean;
}

export interface CollectionData {
name: string;
id: string;
Expand All @@ -56,8 +37,30 @@ export interface ReplicaInfo {
node_ids: string[];
}

export type TypeParam = string | number;
export type TypeParamKey = 'dim' | 'max_length' | 'max_capacity';
export type TypeParam = string | number | boolean | Record<string, any>;
export type TypeParamKey =
| 'dim'
| 'max_length'
| 'max_capacity'
| 'mmap.enabled';

// returned from milvus
export type FieldSchema = {
type_params: KeyValuePair<TypeParamKey, TypeParam>[];
index_params: KeyValuePair[];
fieldID: string | number;
name: string;
is_primary_key: boolean;
description: string;
data_type: keyof typeof DataType;
autoID: boolean;
state: string;
element_type?: keyof typeof DataType;
dataType: DataType;
is_partition_key?: boolean;
is_dynamic?: boolean;
is_clustering_key?: boolean;
} & Partial<Record<TypeParamKey, TypeParam>>;

// create collection
export interface FieldType {
Expand Down Expand Up @@ -265,3 +268,8 @@ export interface ListAliasesResponse extends resStatusResponse {
aliases: string[];
collection_name: string;
}

export interface AlterCollectionFieldPropertiesReq extends collectionNameReq {
field_name: string; // required, field name
properties: Properties; // required, properties
}
6 changes: 3 additions & 3 deletions milvus/types/Common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ export interface MsgBase {
};
}

export interface KeyValuePair {
key: string;
value: string | number;
export interface KeyValuePair<T = string, U = string | number> {
key: T;
value: U;
}

interface NumberArray {
Expand Down
42 changes: 30 additions & 12 deletions milvus/utils/Format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ import {
bf16BytesToF32Array,
f16BytesToF32Array,
keyValueObj,
TypeParamKey,
TypeParam,
} from '../';

/**
Expand Down Expand Up @@ -189,23 +191,33 @@ export const formatAddress = (address: string) => {
*/
export const assignTypeParams = (
field: FieldType,
typeParamKeys: string[] = ['dim', 'max_length', 'max_capacity']
typeParamKeys: TypeParamKey[] = [
'dim',
'max_length',
'max_capacity',
'mmap.enabled',
]
) => {
let newField = cloneObj<FieldType>(field);
const newField = cloneObj<FieldType>(field);

// Initialize `type_params` if undefined
newField.type_params ??= {} as Record<TypeParamKey, TypeParam>;

typeParamKeys.forEach(key => {
if (newField.hasOwnProperty(key)) {
// if the property exists in the field object, assign it to the type_params object
newField.type_params = newField.type_params || {};
newField.type_params[key] = String(newField[key as keyof FieldType]);
// delete the property from the field object
if (key in newField) {
const value = newField[key as keyof FieldType];
// Convert the value to a string, JSON-stringify if it’s an object
newField.type_params![key] =
typeof value === 'object' ? JSON.stringify(value) : String(value ?? '');
delete newField[key as keyof FieldType];
}

if (newField.type_params && newField.type_params[key]) {
// if the property already exists in the type_params object, convert it to a string
newField.type_params[key] = String(newField.type_params[key]);
}
});

// delete type_params if it's empty
if (!Object.keys(newField.type_params).length) {
delete newField.type_params;
}

return newField;
};

Expand Down Expand Up @@ -361,6 +373,12 @@ export const formatDescribedCol = (
// add a dataType property which indicate datatype number
newData.schema?.fields?.forEach(f => {
f.dataType = DataTypeMap[f.data_type];
// extract type params(key value pair = {key: 'xxx', value: any}), and assign it to the field object(key)
if (f.type_params && f.type_params.length > 0) {
f.type_params.forEach(keyValuePair => {
f[keyValuePair.key] = keyValuePair.value;
});
}
});

return newData;
Expand Down
39 changes: 38 additions & 1 deletion test/grpc/Collection.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ describe(`Collection API`, () => {

expect(
Boolean(
formatKeyValueData(describe.properties, ['mmap.enabled'])['mmap.enabled']
formatKeyValueData(describe.properties, ['mmap.enabled'])[
'mmap.enabled'
]
)
).toEqual(true);
});
Expand Down Expand Up @@ -434,6 +436,41 @@ describe(`Collection API`, () => {
).toEqual(value2);
});

it(`Alter collection field properties should success`, async () => {
const key = 'mmap.enabled';
const value = true;
const alter = await milvusClient.alterCollectionFieldProperties({
collection_name: LOAD_COLLECTION_NAME,
field_name: 'json',
properties: { [key]: value },
db_name: 'Collection', // pass test case
});
expect(alter.error_code).toEqual(ErrorCode.SUCCESS);
const describe = await milvusClient.describeCollection({
collection_name: LOAD_COLLECTION_NAME,
});
// find json field
const jsonField = describe.schema.fields.find(
f => f.name === 'json'
) as any;
expect(jsonField['mmap.enabled']).toEqual('true');
const alter2 = await milvusClient.alterCollectionFieldProperties({
collection_name: LOAD_COLLECTION_NAME,
field_name: 'varChar',
properties: { max_length: 1024 },
db_name: 'Collection', // pass test case
});
expect(alter2.error_code).toEqual(ErrorCode.SUCCESS);
const describe2 = await milvusClient.describeCollection({
collection_name: LOAD_COLLECTION_NAME,
});
// find varChar field
const varCharField = describe2.schema.fields.find(
f => f.name === 'varChar'
) as any;
expect(varCharField['max_length']).toEqual('1024');
});

it(`Load Collection Sync throw COLLECTION_NAME_IS_REQUIRED`, async () => {
try {
await milvusClient.loadCollectionSync({} as any);
Expand Down
3 changes: 3 additions & 0 deletions test/utils/Format.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ describe('utils/format', () => {
type_params: {
dim: 100,
max_length: 50,
'mmap.enabled': true,
},
dim: 200,
max_length: 75,
Expand All @@ -214,6 +215,7 @@ describe('utils/format', () => {
type_params: {
dim: '200',
max_length: '75',
'mmap.enabled': true,
},
};
expect(assignTypeParams(field)).toEqual(expectedOutput);
Expand Down Expand Up @@ -414,6 +416,7 @@ describe('utils/format', () => {
const formatted = formatDescribedCol(response);

expect(formatted.schema.fields[0].dataType).toBe(101);
expect(formatted.schema.fields[0].dim).toBe('128');
expect(formatted.schema.fields[1].dataType).toBe(5);
});

Expand Down

0 comments on commit 889fe0c

Please sign in to comment.