diff --git a/client/src/consts/Milvus.ts b/client/src/consts/Milvus.ts index a5f674dc..5c106dd4 100644 --- a/client/src/consts/Milvus.ts +++ b/client/src/consts/Milvus.ts @@ -121,7 +121,12 @@ export type searchKeywordsType = | 'radius' | 'range_filter' | 'drop_ratio_search' - | 'filter'; + | 'filter' + | 'itopk_size' + | 'search_width' + | 'min_iterations' + | 'max_iterations' + | 'team_size'; export type indexConfigType = { [x: string]: { @@ -132,9 +137,13 @@ export type indexConfigType = { // index export const FLOAT_INDEX_CONFIG: indexConfigType = { - SCANN: { - create: ['nlist', 'with_raw_data'], - search: ['nprobe'], + AUTOINDEX: { + create: [], + search: ['level'], + }, + HNSW: { + create: ['M', 'efConstruction'], + search: ['ef'], }, IVF_FLAT: { create: ['nlist'], @@ -152,22 +161,50 @@ export const FLOAT_INDEX_CONFIG: indexConfigType = { create: [], search: ['nprobe'], }, - HNSW: { - create: ['M', 'efConstruction'], - search: ['ef'], - }, - AUTOINDEX: { - create: [], - search: ['level'], + SCANN: { + create: ['nlist', 'with_raw_data'], + search: ['nprobe'], }, +}; + +export const DISK_INDEX_CONFIG: indexConfigType = { DISKANN: { create: [], search: ['search_list'], }, }; +export const GPU_INDEX_CONFIG: indexConfigType = { + GPU_CAGRA: { + create: [ + 'intermediate_graph_degree', + 'graph_degree', + 'build_algo', + 'cache_dataset_on_device', + ], + search: [ + 'itopk_size', + 'search_width', + 'min_iterations', + 'max_iterations', + 'team_size', + ], + }, + GPU_IVF_FLAT: { + create: ['nlist'], + search: ['nprobe'], + }, + GPU_IVF_PQ: { + create: ['nlist', 'm', 'nbits'], + search: ['nprobe'], + }, + GPU_BRUTE_FORCE: { + create: [], + search: [], + }, +}; + export const BINARY_INDEX_CONFIG: indexConfigType = { - // }, BIN_FLAT: { create: [], search: [], @@ -193,6 +230,8 @@ export const INDEX_CONFIG: indexConfigType = { ...FLOAT_INDEX_CONFIG, ...BINARY_INDEX_CONFIG, ...SPARSE_INDEX_CONFIG, + ...DISK_INDEX_CONFIG, + ...GPU_INDEX_CONFIG, }; export const COLLECTION_NAME_REGX = /^[0-9,a-z,A-Z$_]+$/; @@ -224,6 +263,14 @@ export const INDEX_OPTIONS_MAP = { value: INDEX_TYPES_ENUM.MARISA_TRIE, }, ], + ['DISK']: Object.keys(DISK_INDEX_CONFIG).map(v => ({ + label: v, + value: v, + })), + ['GPU']: Object.keys(GPU_INDEX_CONFIG).map(v => ({ + label: v, + value: v, + })), }; // search params default value map diff --git a/client/src/i18n/cn/index.ts b/client/src/i18n/cn/index.ts index 86b9274c..d05f0e58 100644 --- a/client/src/i18n/cn/index.ts +++ b/client/src/i18n/cn/index.ts @@ -1,6 +1,10 @@ const indexTrans = { type: '索引类型', param: '索引参数', + inMemory: '内存索引', + disk: '磁盘索引', + gpu: 'GPU索引', + scalar: '标量索引', create: '创建索引', index: '索引', diff --git a/client/src/i18n/en/index.ts b/client/src/i18n/en/index.ts index 3041a948..8645c9f3 100644 --- a/client/src/i18n/en/index.ts +++ b/client/src/i18n/en/index.ts @@ -1,6 +1,10 @@ const indexTrans = { type: 'Index Type', param: 'Index Parameters', + inMemory: 'In-Memory Index', + disk: 'Disk Index', + gpu: 'GPU Index', + scalar: 'Scalar Index', create: 'Create Index', index: 'Index', diff --git a/client/src/pages/databases/collections/overview/CreateForm.tsx b/client/src/pages/databases/collections/overview/CreateForm.tsx index a655741d..7283171b 100644 --- a/client/src/pages/databases/collections/overview/CreateForm.tsx +++ b/client/src/pages/databases/collections/overview/CreateForm.tsx @@ -4,7 +4,8 @@ import { useTranslation } from 'react-i18next'; import { ITextfieldConfig } from '@/components/customInput/Types'; import CustomInput from '@/components/customInput/CustomInput'; import CustomSelector from '@/components/customSelector/CustomSelector'; -import { Option } from '@/components/customSelector/Types'; +import CustomGroupedSelect from '@/components/customSelector/CustomGroupedSelect'; +import { Option, GroupOption } from '@/components/customSelector/Types'; import { FormHelperType } from '../../../../types/Common'; const useStyles = makeStyles((theme: Theme) => ({ @@ -26,7 +27,7 @@ const useStyles = makeStyles((theme: Theme) => ({ const CreateForm = ( props: FormHelperType & { metricOptions: Option[]; - indexOptions: Option[]; + indexOptions: GroupOption[]; indexParams: string[]; indexTypeChange?: (type: string) => void; } @@ -76,6 +77,16 @@ const CreateForm = ( }; if (type === 'number') { + config.validations!.push({ + rule: 'number', + errorText: warningTrans('number', { name: label }), + }); + } + if ( + type === 'number' && + typeof min === 'number' && + typeof max === 'number' + ) { config.validations!.push({ rule: 'range', errorText: warningTrans('range', { min, max }), @@ -157,6 +168,24 @@ const CreateForm = ( key: 'with_raw_data', type: 'bool', }), + intermediate_graph_degree: generateConfig({ + label: 'intermediate_graph_degree', + key: 'intermediate_graph_degree', + }), + graph_degree: generateConfig({ + label: 'graph_degree', + key: 'graph_degree', + }), + build_algo: generateConfig({ + label: 'build_algo', + key: 'build_algo', + type: 'text', + }), + cache_dataset_on_device: generateConfig({ + label: 'cache_dataset_on_device', + key: 'cache_dataset_on_device', + type: 'bool', + }), }; const result: ITextfieldConfig[] = []; @@ -182,10 +211,10 @@ const CreateForm = ( return (
- { const type = e.target.value; updateForm('index_type', type as string); @@ -193,8 +222,7 @@ const CreateForm = ( updateForm('metric_type', metricOptions[0].value as string); indexTypeChange && indexTypeChange(type as string); }} - variant="filled" - wrapperClass={classes.select} + className={classes.select} /> [ + { label, children }, + ]; + const indexOptions = useMemo(() => { - switch (fieldType) { - case DataTypeStringEnum.BinaryVector: - return INDEX_OPTIONS_MAP[DataTypeEnum.BinaryVector]; - case DataTypeStringEnum.FloatVector: - case DataTypeStringEnum.Float16Vector: - case DataTypeStringEnum.BFloat16Vector: - return INDEX_OPTIONS_MAP[DataTypeEnum.FloatVector]; - case DataTypeStringEnum.SparseFloatVector: - return INDEX_OPTIONS_MAP[DataTypeEnum.SparseFloatVector]; - case DataTypeStringEnum.VarChar: - return INDEX_OPTIONS_MAP[DataTypeEnum.VarChar]; + if (VectorTypes.includes(dataType)) { + switch (fieldType) { + case DataTypeStringEnum.BinaryVector: + return [ + ...getOptions( + indexTrans('inMemory'), + INDEX_OPTIONS_MAP[DataTypeEnum.BinaryVector] + ), + ]; + case DataTypeStringEnum.SparseFloatVector: + return [ + ...getOptions( + indexTrans('inMemory'), + INDEX_OPTIONS_MAP[DataTypeEnum.SparseFloatVector] + ), + ]; - default: - return [ - { label: 'INVERTED', value: INDEX_TYPES_ENUM.INVERTED }, - { label: 'STL sort', value: INDEX_TYPES_ENUM.SORT }, - ]; + default: + return [ + ...getOptions( + indexTrans('inMemory'), + INDEX_OPTIONS_MAP[DataTypeEnum.FloatVector] + ), + ...getOptions(indexTrans('disk'), INDEX_OPTIONS_MAP['DISK']), + ...getOptions(indexTrans('gpu'), INDEX_OPTIONS_MAP['GPU']), + ]; + } + } else { + switch (fieldType) { + case DataTypeStringEnum.VarChar: + return getOptions( + indexTrans('scalar'), + INDEX_OPTIONS_MAP[DataTypeEnum.VarChar] + ); + default: + return getOptions(indexTrans('scalar'), [ + { label: 'INVERTED', value: INDEX_TYPES_ENUM.INVERTED }, + { label: 'STL sort', value: INDEX_TYPES_ENUM.SORT }, + ]); + } } - }, [fieldType]); + }, [fieldType, dataType, fieldName]); const checkedForm = useMemo(() => { if (!VectorTypes.includes(dataType)) { @@ -241,8 +273,8 @@ const CreateIndex = (props: { }, 0); }; - const handleCreateIndex = () => { - handleCreate(extraParams, indexSetting.index_name); + const handleCreateIndex = async () => { + await handleCreate(extraParams, indexSetting.index_name); }; const handleShowCode = (event: React.ChangeEvent<{ checked: boolean }>) => { diff --git a/client/src/pages/databases/collections/overview/IndexTypeElement.tsx b/client/src/pages/databases/collections/overview/IndexTypeElement.tsx index d458cae8..8ebc3c31 100644 --- a/client/src/pages/databases/collections/overview/IndexTypeElement.tsx +++ b/client/src/pages/databases/collections/overview/IndexTypeElement.tsx @@ -13,7 +13,7 @@ import { DataTypeStringEnum, DataTypeEnum, } from '@/consts'; -import CreateIndex from './Create'; +import CreateIndexDialog from './CreateIndexDialog'; import { FieldObject } from '@server/types'; import CustomButton from '@/components/customButton/CustomButton'; @@ -106,7 +106,7 @@ const IndexTypeElement: FC<{ type: 'custom', params: { component: ( - = ({ handleInputChange('drop_ratio_search', value); }, }, + itopk_size: { + label: 'itopk_size', + key: 'itopk_size', + value: searchParamsForm['itopk_size'] ?? '', + isInt: true, + type: 'number', + required: false, + handleChange: value => { + handleInputChange('itopk_size', value); + }, + }, + search_width: { + label: 'search_width', + key: 'search_width', + value: searchParamsForm['search_width'] ?? '', + isInt: true, + type: 'number', + required: false, + handleChange: value => { + handleInputChange('search_width', value); + }, + }, + min_iterations: { + label: 'min_iterations', + key: 'min_iterations', + value: searchParamsForm['min_iterations'] ?? '0', + isInt: true, + type: 'number', + required: false, + handleChange: value => { + handleInputChange('min_iterations', value); + }, + }, + max_iterations: { + label: 'max_iterations', + key: 'max_iterations', + value: searchParamsForm['max_iterations'] ?? '0', + isInt: true, + type: 'number', + required: false, + handleChange: value => { + handleInputChange('max_iterations', value); + }, + }, + team_size: { + label: 'team_size', + key: 'team_size', + value: searchParamsForm['team_size'] ?? '0', + min: 2, + max: 32, + isInt: true, + type: 'number', + required: false, + handleChange: value => { + handleInputChange('team_size', value); + }, + }, }; const param = configParamMap[paramKey];