Browse Source

refactor: create index dialog and search params inputs (#891)

* refactor create index dialog

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* add i18n

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* refactor search params part1

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* fix search params

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* update create index dialog

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* finish

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

---------

Signed-off-by: ryjiang <jiangruiyi@gmail.com>
ryjiang 1 month ago
parent
commit
ae17a977f7

+ 79 - 222
client/src/consts/Milvus.ts

@@ -38,36 +38,46 @@ export const VectorTypes = [
 ];
 ];
 
 
 export enum INDEX_TYPES_ENUM {
 export enum INDEX_TYPES_ENUM {
-  AUTOINDEX = 'AUTOINDEX',
+  // Vector indexes
+  FLAT = 'FLAT',
   IVF_FLAT = 'IVF_FLAT',
   IVF_FLAT = 'IVF_FLAT',
-  IVF_PQ = 'IVF_PQ',
   IVF_SQ8 = 'IVF_SQ8',
   IVF_SQ8 = 'IVF_SQ8',
-  IVF_SQ8_HYBRID = 'IVF_SQ8_HYBRID',
-  FLAT = 'FLAT',
+  IVF_PQ = 'IVF_PQ',
   HNSW = 'HNSW',
   HNSW = 'HNSW',
-  ANNOY = 'ANNOY',
-  RNSG = 'RNSG',
-  BIN_IVF_FLAT = 'BIN_IVF_FLAT',
+  HNSW_SQ = 'HNSW_SQ',
+  HNSW_PQ = 'HNSW_PQ',
+  HNSW_PRQ = 'HNSW_PRQ',
+  SCANN = 'SCANN',
+  DISKANN = 'DISKANN',
+  // GPU indexes
+  GPU_CAGRA = 'GPU_CAGRA',
+  GPU_IVF_FLAT = 'GPU_IVF_FLAT',
+  GPU_IVF_PQ = 'GPU_IVF_PQ',
+  // Binary vector indexes
   BIN_FLAT = 'BIN_FLAT',
   BIN_FLAT = 'BIN_FLAT',
-  SORT = 'STL_SORT',
-  MARISA_TRIE = 'Trie',
-  // sparse
-  SPARSE_INVERTED_INDEX = 'SPARSE_INVERTED_INDEX',
-  SPARSE_WAND = 'SPARSE_WAND',
-  // inverted
+  BIN_IVF_FLAT = 'BIN_IVF_FLAT',
+  // Scalar indexes
   INVERTED = 'INVERTED',
   INVERTED = 'INVERTED',
+  STL_SORT = 'STL_SORT',
+  Trie = 'Trie',
   BITMAP = 'BITMAP',
   BITMAP = 'BITMAP',
+  // Sparse vector indexes
+  SPARSE_INVERTED_INDEX = 'SPARSE_INVERTED_INDEX',
+  // Auto index
+  AUTOINDEX = 'AUTOINDEX',
 }
 }
 
 
 export enum METRIC_TYPES_VALUES {
 export enum METRIC_TYPES_VALUES {
+  // Vector metrics
   L2 = 'L2',
   L2 = 'L2',
   IP = 'IP',
   IP = 'IP',
   COSINE = 'COSINE',
   COSINE = 'COSINE',
+  // Binary vector metrics
   HAMMING = 'HAMMING',
   HAMMING = 'HAMMING',
   JACCARD = 'JACCARD',
   JACCARD = 'JACCARD',
   TANIMOTO = 'TANIMOTO',
   TANIMOTO = 'TANIMOTO',
-  SUBSTRUCTURE = 'SUBSTRUCTURE',
-  SUPERSTRUCTURE = 'SUPERSTRUCTURE',
+  // Sparse vector metrics
+  IP_SPARSE = 'IP_SPARSE',
   BM25 = 'BM25',
   BM25 = 'BM25',
 }
 }
 
 
@@ -75,237 +85,45 @@ export const METRIC_TYPES = [
   {
   {
     value: METRIC_TYPES_VALUES.L2,
     value: METRIC_TYPES_VALUES.L2,
     label: 'L2',
     label: 'L2',
+    description: 'Euclidean distance',
   },
   },
   {
   {
     value: METRIC_TYPES_VALUES.IP,
     value: METRIC_TYPES_VALUES.IP,
     label: 'IP',
     label: 'IP',
+    description: 'Inner product',
   },
   },
   {
   {
     value: METRIC_TYPES_VALUES.COSINE,
     value: METRIC_TYPES_VALUES.COSINE,
     label: 'COSINE',
     label: 'COSINE',
-  },
-  {
-    value: METRIC_TYPES_VALUES.SUBSTRUCTURE,
-    label: 'SUBSTRUCTURE',
-  },
-  {
-    value: METRIC_TYPES_VALUES.SUPERSTRUCTURE,
-    label: 'SUPERSTRUCTURE',
+    description: 'Cosine similarity',
   },
   },
   {
   {
     value: METRIC_TYPES_VALUES.HAMMING,
     value: METRIC_TYPES_VALUES.HAMMING,
     label: 'HAMMING',
     label: 'HAMMING',
+    description: 'Hamming distance',
   },
   },
   {
   {
     value: METRIC_TYPES_VALUES.JACCARD,
     value: METRIC_TYPES_VALUES.JACCARD,
     label: 'JACCARD',
     label: 'JACCARD',
+    description: 'Jaccard distance',
   },
   },
   {
   {
     value: METRIC_TYPES_VALUES.TANIMOTO,
     value: METRIC_TYPES_VALUES.TANIMOTO,
     label: 'TANIMOTO',
     label: 'TANIMOTO',
+    description: 'Tanimoto distance',
+  },
+  {
+    value: METRIC_TYPES_VALUES.IP_SPARSE,
+    label: 'IP_SPARSE',
+    description: 'Inner product for sparse vectors',
   },
   },
   {
   {
     value: METRIC_TYPES_VALUES.BM25,
     value: METRIC_TYPES_VALUES.BM25,
     label: 'BM25',
     label: 'BM25',
+    description: 'BM25 scoring for sparse vectors',
   },
   },
 ];
 ];
 
 
-export type MetricType =
-  | 'L2'
-  | 'IP'
-  | 'COSINE'
-  | 'HAMMING'
-  | 'SUBSTRUCTURE'
-  | 'SUPERSTRUCTURE'
-  | 'JACCARD'
-  | 'TANIMOTO';
-
-export type searchKeywordsType =
-  | 'nprobe'
-  | 'ef'
-  | 'search_k'
-  | 'search_length'
-  | 'round_decimal'
-  | 'level'
-  | 'search_list'
-  | 'radius'
-  | 'range_filter'
-  | 'drop_ratio_search'
-  | 'filter'
-  | 'itopk_size'
-  | 'search_width'
-  | 'min_iterations'
-  | 'max_iterations'
-  | 'team_size';
-
-export type indexConfigType = {
-  [x: string]: {
-    create: string[];
-    search: searchKeywordsType[];
-  };
-};
-
-// index
-const AUTOINDEX_CONFIG: indexConfigType = {
-  AUTOINDEX: {
-    create: [],
-    search: ['level'],
-  },
-};
-export const FLOAT_INDEX_CONFIG: indexConfigType = {
-  HNSW: {
-    create: ['M', 'efConstruction'],
-    search: ['ef'],
-  },
-  IVF_FLAT: {
-    create: ['nlist'],
-    search: ['nprobe'],
-  },
-  IVF_PQ: {
-    create: ['nlist', 'm', 'nbits'],
-    search: ['nprobe'],
-  },
-  IVF_SQ8: {
-    create: ['nlist'],
-    search: ['nprobe'],
-  },
-  FLAT: {
-    create: [],
-    search: ['nprobe'],
-  },
-  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: [],
-  },
-  BIN_IVF_FLAT: {
-    create: ['nlist'],
-    search: ['nprobe'],
-  },
-};
-
-export const SPARSE_INDEX_CONFIG: indexConfigType = {
-  SPARSE_INVERTED_INDEX: {
-    create: ['drop_ratio_build'],
-    search: ['drop_ratio_search'],
-  },
-  SPARSE_WAND: {
-    create: ['drop_ratio_build'],
-    search: ['drop_ratio_search'],
-  },
-};
-
-export const INDEX_CONFIG: indexConfigType = {
-  ...AUTOINDEX_CONFIG,
-  ...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$_]+$/;
-
-export const m_OPTIONS = [
-  { label: '64', value: 64 },
-  { label: '32', value: 32 },
-  { label: '16', value: 16 },
-  { label: '8', value: 8 },
-  { label: '4', value: 4 },
-];
-
-export const INDEX_OPTIONS_MAP = {
-  ['AUTOINDEX']: [{ label: 'AUTOINDEX', value: INDEX_TYPES_ENUM.AUTOINDEX }],
-  [DataTypeEnum.FloatVector]: Object.keys(FLOAT_INDEX_CONFIG).map(v => ({
-    label: v,
-    value: v,
-  })),
-  [DataTypeEnum.BinaryVector]: Object.keys(BINARY_INDEX_CONFIG).map(v => ({
-    label: v,
-    value: v,
-  })),
-  [DataTypeEnum.SparseFloatVector]: Object.keys(SPARSE_INDEX_CONFIG).map(v => ({
-    label: v,
-    value: v,
-  })),
-  ['DISK']: Object.keys(DISK_INDEX_CONFIG).map(v => ({
-    label: v,
-    value: v,
-  })),
-  ['GPU']: Object.keys(GPU_INDEX_CONFIG).map(v => ({
-    label: v,
-    value: v,
-  })),
-};
-
-export const SCALAR_INDEX_OPTIONS = [
-  { label: INDEX_TYPES_ENUM.INVERTED, value: INDEX_TYPES_ENUM.INVERTED },
-  { label: INDEX_TYPES_ENUM.SORT, value: INDEX_TYPES_ENUM.SORT },
-  { label: INDEX_TYPES_ENUM.MARISA_TRIE, value: INDEX_TYPES_ENUM.MARISA_TRIE },
-  { label: INDEX_TYPES_ENUM.BITMAP, value: INDEX_TYPES_ENUM.BITMAP },
-];
-
-// search params default value map
-export const DEFAULT_SEARCH_PARAM_VALUE_MAP: {
-  [key in searchKeywordsType]?: number;
-} = {
-  // range: [top_k, 32768]
-  ef: 250,
-  // range: [1, nlist]
-  nprobe: 1,
-  // range: {-1} ∪ [top_k, n × n_trees]
-  search_k: 250,
-  // range: [10, 300]
-  search_length: 10,
-  level: 1,
-  search_list: 150,
-};
-
-export const DEFAULT_NLIST_VALUE = 1024;
-
 export enum LOADING_STATE {
 export enum LOADING_STATE {
   LOADED = 'loaded',
   LOADED = 'loaded',
   LOADING = 'loading',
   LOADING = 'loading',
@@ -318,10 +136,7 @@ export enum LOAD_STATE {
   LoadStateLoaded = 'LoadStateLoaded',
   LoadStateLoaded = 'LoadStateLoaded',
 }
 }
 
 
-export const DEFAULT_VECTORS = 100000;
-export const DEFAULT_SEFMENT_FILE_SIZE = 1024;
 export const DEFAULT_MILVUS_PORT = 19530;
 export const DEFAULT_MILVUS_PORT = 19530;
-export const DEFAULT_PROMETHEUS_PORT = 9090;
 
 
 export enum MILVUS_NODE_TYPE {
 export enum MILVUS_NODE_TYPE {
   ROOTCOORD = 'rootcoord',
   ROOTCOORD = 'rootcoord',
@@ -491,3 +306,45 @@ export enum IndexState {
   Default = '',
   Default = '',
   Delete = 'Delete',
   Delete = 'Delete',
 }
 }
+
+export const INDEX_OPTIONS_MAP = {
+  ['AUTOINDEX']: [{ label: 'AUTOINDEX', value: INDEX_TYPES_ENUM.AUTOINDEX }],
+  [DataTypeEnum.FloatVector]: [
+    { label: INDEX_TYPES_ENUM.FLAT, value: INDEX_TYPES_ENUM.FLAT },
+    { label: INDEX_TYPES_ENUM.IVF_FLAT, value: INDEX_TYPES_ENUM.IVF_FLAT },
+    { label: INDEX_TYPES_ENUM.IVF_SQ8, value: INDEX_TYPES_ENUM.IVF_SQ8 },
+    { label: INDEX_TYPES_ENUM.IVF_PQ, value: INDEX_TYPES_ENUM.IVF_PQ },
+    { label: INDEX_TYPES_ENUM.HNSW, value: INDEX_TYPES_ENUM.HNSW },
+    { label: INDEX_TYPES_ENUM.HNSW_SQ, value: INDEX_TYPES_ENUM.HNSW_SQ },
+    { label: INDEX_TYPES_ENUM.HNSW_PQ, value: INDEX_TYPES_ENUM.HNSW_PQ },
+    { label: INDEX_TYPES_ENUM.HNSW_PRQ, value: INDEX_TYPES_ENUM.HNSW_PRQ },
+    { label: INDEX_TYPES_ENUM.SCANN, value: INDEX_TYPES_ENUM.SCANN },
+    { label: INDEX_TYPES_ENUM.DISKANN, value: INDEX_TYPES_ENUM.DISKANN },
+    { label: INDEX_TYPES_ENUM.GPU_CAGRA, value: INDEX_TYPES_ENUM.GPU_CAGRA },
+    {
+      label: INDEX_TYPES_ENUM.GPU_IVF_FLAT,
+      value: INDEX_TYPES_ENUM.GPU_IVF_FLAT,
+    },
+    { label: INDEX_TYPES_ENUM.GPU_IVF_PQ, value: INDEX_TYPES_ENUM.GPU_IVF_PQ },
+  ],
+  [DataTypeEnum.BinaryVector]: [
+    { label: INDEX_TYPES_ENUM.BIN_FLAT, value: INDEX_TYPES_ENUM.BIN_FLAT },
+    {
+      label: INDEX_TYPES_ENUM.BIN_IVF_FLAT,
+      value: INDEX_TYPES_ENUM.BIN_IVF_FLAT,
+    },
+  ],
+  [DataTypeEnum.SparseFloatVector]: [
+    {
+      label: INDEX_TYPES_ENUM.SPARSE_INVERTED_INDEX,
+      value: INDEX_TYPES_ENUM.SPARSE_INVERTED_INDEX,
+    },
+  ],
+};
+
+export const SCALAR_INDEX_OPTIONS = [
+  { label: INDEX_TYPES_ENUM.INVERTED, value: INDEX_TYPES_ENUM.INVERTED },
+  { label: INDEX_TYPES_ENUM.STL_SORT, value: INDEX_TYPES_ENUM.STL_SORT },
+  { label: INDEX_TYPES_ENUM.Trie, value: INDEX_TYPES_ENUM.Trie },
+  { label: INDEX_TYPES_ENUM.BITMAP, value: INDEX_TYPES_ENUM.BITMAP },
+];

+ 18 - 2
client/src/http/Data.service.ts

@@ -4,8 +4,8 @@ import type {
   InsertDataParam,
   InsertDataParam,
   DeleteEntitiesReq,
   DeleteEntitiesReq,
 } from '@/pages/databases/collections/Types';
 } from '@/pages/databases/collections/Types';
-import type { VectorSearchParam } from '@/types/SearchTypes';
 import { MutationResult, type VectorSearchResults } from '@server/types';
 import { MutationResult, type VectorSearchResults } from '@server/types';
+import { DataTypeEnum } from '@/consts';
 
 
 export class DataService extends BaseModel {
 export class DataService extends BaseModel {
   static importSample(collectionName: string, param: LoadSampleParam) {
   static importSample(collectionName: string, param: LoadSampleParam) {
@@ -51,7 +51,23 @@ export class DataService extends BaseModel {
     });
     });
   }
   }
 
 
-  static vectorSearchData(collectionName: string, params: VectorSearchParam) {
+  static vectorSearchData(
+    collectionName: string,
+    params: {
+      expr?: string;
+      search_params: {
+        anns_field: string; // your vector field name
+        topk: string | number;
+        metric_type: string;
+        params: string;
+      };
+      vectors: any;
+      output_fields: string[];
+      vector_type: DataTypeEnum;
+      travel_timestamp?: string;
+      consistency_level?: string;
+    }
+  ) {
     return super.query<VectorSearchResults>({
     return super.query<VectorSearchResults>({
       path: `/collections/${collectionName}/search`,
       path: `/collections/${collectionName}/search`,
       data: params,
       data: params,

+ 154 - 0
client/src/i18n/cn/index.ts

@@ -18,6 +18,160 @@ const indexTrans = {
   createSuccess: '开始创建索引',
   createSuccess: '开始创建索引',
   deleteWarning: '您正在尝试删除一个索引。此操作无法撤销。',
   deleteWarning: '您正在尝试删除一个索引。此操作无法撤销。',
   cancelCreate: '取消创建索引',
   cancelCreate: '取消创建索引',
+
+  metricType: {
+    type: '度量类型',
+    IP: {
+      description: '内积:基于向量点积的相似度度量。值越大表示相似度越高。',
+    },
+    L2: {
+      description:
+        '欧氏距离:基于向量间直线距离的相似度度量。值越小表示相似度越高。',
+    },
+    COSINE: {
+      description:
+        '余弦相似度:基于向量间夹角余弦的相似度度量。取值范围为-1到1,1表示向量完全相同。',
+    },
+    BM25: {
+      description: 'BM25:基于概率相关性框架的文本搜索排序函数。',
+    },
+  },
+
+  params: {
+    nlist: {
+      description: '使用k-means算法创建的聚类数量。',
+      helperText:
+        '较大的值可以提高召回率但会增加索引构建时间。推荐范围:[1, 65536]。',
+    },
+    nbits: {
+      description: '每个子向量组量化的位数。',
+      helperText: {
+        IVF_PQ: '必须在1到64之间。',
+        common: '必须在1到24之间。',
+      },
+    },
+    M: {
+      description: '图中最大出边数量。',
+      helperText:
+        '在固定的ef/efConstruction下,较大的M值会提高准确率/运行时间。必须在2到2048之间。',
+    },
+    efConstruction: {
+      description: '控制索引搜索速度/构建速度的权衡。',
+      helperText: '必须在1到int_max之间。',
+    },
+    m: {
+      description: '向量被分割成的子向量组数量。',
+      helperText: '必须在1到65536之间。',
+    },
+    sq_type: {
+      description: '标量量化器类型。',
+      helperText: '可用选项:SQ6, SQ8, BF16, FP16。',
+    },
+    refine: {
+      description: '是否在索引构建期间保留精炼数据。',
+      helperText: '如果为true,存储精炼数据以提高准确率但会使用更多内存。',
+    },
+    refine_type: {
+      description: '精炼索引的数据类型。',
+      helperText: '可用选项:SQ6, SQ8, BF16, FP16, FP32。',
+    },
+    nrq: {
+      description: '残差子量化器数量。',
+      helperText:
+        '对残差向量执行的完整PQ量化数量。较高的值会提高准确率但会增加索引大小。',
+    },
+    intermediate_graph_degree: {
+      description: '剪枝前的图度数。',
+      helperText: '影响召回率和构建时间。推荐值:32或64。',
+    },
+    graph_degree: {
+      description: '剪枝后的图度数。',
+      helperText: '必须小于intermediate_graph_degree。影响搜索性能和召回率。',
+    },
+    build_algo: {
+      description: '剪枝前的图生成算法。',
+      helperText:
+        'IVF_PQ:更高质量但构建时间较慢。NN_DESCENT:构建更快但召回率可能较低。',
+    },
+    cache_dataset_on_device: {
+      description: '是否在GPU内存中缓存原始数据集。',
+      helperText: 'true:通过精炼搜索结果提高召回率。false:节省GPU内存。',
+    },
+    adapt_for_cpu: {
+      description: '是否使用GPU构建索引并使用CPU搜索。',
+      helperText: '如果为true,需要在搜索请求中提供ef参数。',
+    },
+    with_raw_data: {
+      description: '是否存储原始数据。',
+    },
+  },
+  searchParams: {
+    nprobe: {
+      description: '查询的单元数量。',
+      helperText: '必须在1到65536之间。',
+    },
+    efConstruction: {
+      description: '控制搜索速度与索引构建速度的权衡。',
+      helperText:
+        '增加efConstruction参数可能提升索引质量,但也会延长构建时间。',
+    },
+    max_empty_result_buckets: {
+      description:
+        '连续未返回结果的桶数量上限(范围搜索参数)。当连续空桶数达到该值时终止搜索。增大此值可提高召回率,但会增加搜索耗时。',
+      helperText: '必须在1到65535之间。',
+    },
+    reorder_k: {
+      description:
+        '搜索过程中重排序的向量数量。增大该值可能提升搜索精度,但会增加搜索时间。',
+      helperText: '必须在1到65536之间。',
+    },
+    refine_k: {
+      description:
+        '搜索过程中优化的向量数量。增大该值可能提升搜索精度,但会增加搜索时间。',
+      helperText: '必须在1到65536之间。',
+    },
+    itopk_size: {
+      description:
+        '搜索过程中保留的中间结果数量。增大该值可能提升召回率,但会降低搜索性能。建议至少等于最终top-k(limit)值,通常取2的幂次方(如16/32/64/128)。',
+      helperText: '必须在1到2147483647之间。',
+    },
+    search_width: {
+      description:
+        '指定CAGRA图搜索时的入口点数量(如1/2/4/8/16/32)。增大该值可提高召回率,但可能影响搜索性能。',
+      helperText: '必须在1到2147483647之间。',
+    },
+    team_size: {
+      description:
+        '指定GPU上计算度量距离的CUDA线程数(建议取2的幂次方,最大32)。对搜索性能影响较小。默认值0表示由Milvus根据向量维度自动选择。',
+      helperText: '必须在0到32之间。',
+    },
+    min_iterations: {
+      description:
+        '控制最小搜索迭代次数(默认0表示CAGRA根据itopk_size和search_width自动计算)。手动调整可平衡性能与精度。',
+      helperText: '必须在0到2147483647之间。',
+    },
+    max_iterations: {
+      description:
+        '控制最大搜索迭代次数(默认0表示CAGRA根据itopk_size和search_width自动计算)。手动调整可平衡性能与精度。',
+      helperText: '必须在0到2147483647之间。',
+    },
+    radius: {
+      description: '搜索半径。',
+      helperText: '',
+    },
+    range_filter: {
+      description: '搜索范围。',
+      helperText: '',
+    },
+    search_list: {
+      description: '候选列表大小,较大的值可以提高召回率,但会降低搜索性能。',
+      helperText: '必须在TopK到2147483647之间。',
+    },
+    level: {
+      description: '增加level参数将提高召回率,但可能会降低搜索性能。',
+      helperText: '必须在1到10之间。',
+    },
+  },
 };
 };
 
 
 export default indexTrans;
 export default indexTrans;

+ 162 - 0
client/src/i18n/en/index.ts

@@ -19,6 +19,168 @@ const indexTrans = {
   deleteWarning:
   deleteWarning:
     'You are trying to delete an index. This action cannot be undone.',
     'You are trying to delete an index. This action cannot be undone.',
   cancelCreate: 'Cancel Index Creation',
   cancelCreate: 'Cancel Index Creation',
+
+  metricType: {
+    IP: {
+      description:
+        'Measures similarity based on the dot product of vectors. Higher values indicate greater similarity.',
+    },
+    L2: {
+      description:
+        'Measures similarity based on the straight-line distance between vectors. Lower values indicate greater similarity.',
+    },
+    COSINE: {
+      description:
+        'Measures similarity based on the cosine of the angle between vectors. Values range from -1 to 1, with 1 indicating identical vectors.',
+    },
+    BM25: {
+      description:
+        'BM25: A ranking function used for text search, based on the probabilistic relevance framework.',
+    },
+  },
+
+  params: {
+    nlist: {
+      description: 'Number of clusters to create using k-means algorithm.',
+      helperText:
+        'Larger values improve recall but increase index building time. Recommended range: [1, 65536].',
+    },
+    nbits: {
+      description:
+        'The number of bits into which each group of sub-vectors is quantized.',
+      helperText: {
+        IVF_PQ: 'Must be between 1 and 64.',
+        common: 'Must be between 1 and 24.',
+      },
+    },
+    M: {
+      description: 'Maximum number of outgoing connections in the graph.',
+      helperText:
+        'Higher M leads to higher accuracy/run_time at fixed ef/efConstruction. Must be between 2 and 2048.',
+    },
+    efConstruction: {
+      description: 'Controls index search speed/build speed tradeoff.',
+      helperText: 'Must be between 1 and int_max.',
+    },
+    m: {
+      description: 'The number of sub-vector groups to split the vector into.',
+      helperText: 'Must be between 1 and 65536.',
+    },
+    sq_type: {
+      description: 'Scalar quantizer type.',
+      helperText: 'Available options: SQ6, SQ8, BF16, FP16.',
+    },
+    refine: {
+      description: 'Whether refined data is reserved during index building.',
+      helperText:
+        'If true, stores refined data for better accuracy but uses more memory.',
+    },
+    refine_type: {
+      description: 'The data type of the refine index.',
+      helperText: 'Available options: SQ6, SQ8, BF16, FP16, FP32.',
+    },
+    nrq: {
+      description: 'The number of residual subquantizers.',
+      helperText:
+        'Number of complete PQ quantizations to perform on residual vectors. Higher values improve accuracy but increase index size.',
+    },
+    intermediate_graph_degree: {
+      description: 'Graph degree before pruning.',
+      helperText:
+        'Affects recall and build time. Recommended values: 32 or 64.',
+    },
+    graph_degree: {
+      description: 'Graph degree after pruning.',
+      helperText:
+        'Must be smaller than intermediate_graph_degree. Affects search performance and recall.',
+    },
+    build_algo: {
+      description: 'Graph generation algorithm before pruning.',
+      helperText:
+        'IVF_PQ: Higher quality but slower build time. NN_DESCENT: Quicker build with potentially lower recall.',
+    },
+    cache_dataset_on_device: {
+      description: 'Whether to cache the original dataset in GPU memory.',
+      helperText:
+        'true: Enhances recall by refining search results. false: Saves GPU memory.',
+    },
+    adapt_for_cpu: {
+      description: 'Whether to use GPU for index-building and CPU for search.',
+      helperText: 'If true, requires ef parameter in search requests.',
+    },
+    with_raw_data: {
+      description: 'Whether to store raw data.',
+    },
+  },
+  searchParams: {
+    nprobe: {
+      description: 'The number of units to query.',
+      helperText: 'Must be between 1 and 65536.',
+    },
+    efConstruction: {
+      description: 'Controls search speed/build speed tradeoff.',
+      helperText:
+        'Increasing the efConstruction parameter may enhance index quality, but it also tends to lengthen the indexing time.',
+    },
+    max_empty_result_buckets: {
+      description:
+        'Maximum number of buckets not returning any search results. This is a range-search parameter and terminates the search process whilst the number of consecutive empty buckets reaches the specified value. Increasing this value can improve recall rate at the cost of increased search time.',
+      helperText: 'Must be between 1 and 65535.',
+    },
+    reorder_k: {
+      description:
+        'The number of vectors to reorder during search. A larger value may improve search accuracy but will increase search time.',
+      helperText: 'Must be between 1 and 65536.',
+    },
+    refine_k: {
+      description:
+        'The number of vectors to refine during search. A larger value may improve search accuracy but will increase search time.',
+      helperText: 'Must be between 1 and 65536.',
+    },
+    itopk_size: {
+      description:
+        'Determines the size of intermediate results kept during the search. A larger value may improve recall at the expense of search performance. It should be at least equal to the final top-k (limit) value and is typically a power of 2 (e.g., 16, 32, 64, 128).',
+      helperText: 'Must be between 1 and 2147483647.',
+    },
+    search_width: {
+      description:
+        'Specifies the number of entry points into the CAGRA graph during the search. Increasing this value can enhance recall but may impact search performance (e.g. 1, 2, 4, 8, 16, 32).',
+      helperText: 'Must be between 1 and 2147483647.',
+    },
+    team_size: {
+      description:
+        'Specifies the number of CUDA threads used for calculating metric distance on the GPU. Common values are a power of 2 up to 32 (e.g. 2, 4, 8, 16, 32). It has a minor impact on search performance. The default value is 0, where Milvus automatically selects the team_size based on the vector dimension.',
+      helperText: 'Must be between 0 and 32.',
+    },
+    min_iterations: {
+      description:
+        'Controls the minimum number of search iterations. By default, it is set to 0, and CAGRA automatically determines the number of iterations based on itopk_size and search_width. Adjusting this value manually can help balance performance and accuracy.',
+      helperText: 'Must be between 0 and 2147483647.',
+    },
+    max_iterations: {
+      description:
+        'Controls the maximum number of search iterations. By default, it is set to 0, and CAGRA automatically determines the number of iterations based on itopk_size and search_width. Adjusting this value manually can help balance performance and accuracy.',
+      helperText: 'Must be between 0 and 2147483647.',
+    },
+    radius: {
+      description: 'The radius of the search.',
+      helperText: '',
+    },
+    range_filter: {
+      description: 'The range of the search.',
+      helperText: '',
+    },
+    search_list: {
+      description:
+        'Size of the candidate list, a larger size offers a higher recall rate with degraded performance.',
+      helperText: 'Must be between TopK and 2147483647.',
+    },
+    level: {
+      description:
+        'Increasing the level parameter will result in a higher recall rate, but may also lead to degraded search performance.',
+      helperText: 'Must be between 1 and 10.',
+    },
+  },
 };
 };
 
 
 export default indexTrans;
 export default indexTrans;

+ 149 - 225
client/src/pages/databases/collections/schema/CreateForm.tsx

@@ -1,14 +1,21 @@
-import { Theme, Typography } from '@mui/material';
+import {
+  Select,
+  MenuItem,
+  FormControl,
+  InputLabel,
+  ListSubheader,
+  Box,
+  TextField,
+  FormHelperText,
+} from '@mui/material';
 import { useMemo } from 'react';
 import { useMemo } from 'react';
 import { useTranslation } from 'react-i18next';
 import { useTranslation } from 'react-i18next';
-import { ITextfieldConfig } from '@/components/customInput/Types';
-import CustomInput from '@/components/customInput/CustomInput';
-import CustomSelector from '@/components/customSelector/CustomSelector';
-import CustomGroupedSelect from '@/components/customSelector/CustomGroupedSelect';
-import type { FormHelperType } from '../../../../types/Common';
-
 import { useTheme } from '@mui/material';
 import { useTheme } from '@mui/material';
 import type { Option, GroupOption } from '@/components/customSelector/Types';
 import type { Option, GroupOption } from '@/components/customSelector/Types';
+import type { FormHelperType } from '../../../../types/Common';
+import { INDEX_PARAMS_CONFIG } from './indexParamsConfig';
+import IndexParamField from './IndexParamField';
+import { DataTypeEnum } from '@/consts';
 
 
 const CreateForm = (
 const CreateForm = (
   props: FormHelperType & {
   props: FormHelperType & {
@@ -16,248 +23,165 @@ const CreateForm = (
     indexOptions: GroupOption[];
     indexOptions: GroupOption[];
     indexParams: string[];
     indexParams: string[];
     indexTypeChange?: (type: string) => void;
     indexTypeChange?: (type: string) => void;
+    fieldType: DataTypeEnum;
   }
   }
 ) => {
 ) => {
   const theme = useTheme();
   const theme = useTheme();
   const {
   const {
     updateForm,
     updateForm,
     formValue,
     formValue,
-    checkIsValid,
     validation,
     validation,
-    indexParams,
     indexTypeChange,
     indexTypeChange,
     indexOptions,
     indexOptions,
     metricOptions,
     metricOptions,
     wrapperClass,
     wrapperClass,
+    fieldType,
   } = props;
   } = props;
 
 
-  const { t: commonTrans } = useTranslation();
   const { t: indexTrans } = useTranslation('index');
   const { t: indexTrans } = useTranslation('index');
-  const { t: warningTrans } = useTranslation('warning');
-
-  const paramsConfig: ITextfieldConfig[] = useMemo(() => {
-    const generateConfig = (props: {
-      label: string;
-      key: string;
-      min?: number;
-      max?: number;
-      type?: 'number' | 'text' | 'password' | 'bool';
-    }) => {
-      const { label, key, min, max, type = 'number' } = props;
-      const config: ITextfieldConfig = {
-        label,
-        key,
-        onChange: value => {
-          updateForm(key, value);
-        },
-        variant: 'filled',
-        fullWidth: true,
-        type: type,
-        value: formValue[key],
-        validations: [
-          {
-            rule: 'require',
-            errorText: warningTrans('required', { name: label }),
-          },
-        ],
-      };
-
-      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 }),
-          extraParam: {
-            min,
-            max,
-            type: 'number',
-          },
-        });
-      }
-
-      if (type === 'bool') {
-        config.validations!.push({
-          rule: 'bool',
-          errorText: warningTrans('bool', { name: label }),
-        });
-      }
-      return config;
-    };
 
 
-    const paramsMap = {
-      nlist: generateConfig({
-        label: 'nlist',
-        key: 'nlist',
-        min: 1,
-        max: 65536,
-      }),
-      nbits: generateConfig({
-        label: 'nbits',
-        key: 'nbits',
-        min: 1,
-        max: 16,
-      }),
-      M: generateConfig({ label: 'M', key: 'M', min: 2, max: 2048 }),
-      efConstruction: generateConfig({
-        label: 'efConstruction',
-        key: 'efConstruction',
-        min: 1,
-        max: 2147483647,
-      }),
-      n_trees: generateConfig({
-        label: 'n_trees',
-        key: 'n_trees',
-        min: 1,
-        max: 1024,
-      }),
-      out_degree: generateConfig({
-        label: 'out_degree',
-        key: 'out_degree',
-        min: 5,
-        max: 300,
-      }),
-      candidate_pool_size: generateConfig({
-        label: 'candidate_pool_size',
-        key: 'candidate_pool_size',
-        min: 50,
-        max: 1000,
-      }),
-      search_length: generateConfig({
-        label: 'search_length',
-        key: 'search_length',
-        min: 10,
-        max: 300,
-      }),
-      knng: generateConfig({
-        label: 'knng',
-        key: 'knng',
-        min: 5,
-        max: 300,
-      }),
-      drop_ratio_build: generateConfig({
-        label: 'drop_ratio_build',
-        key: 'drop_ratio_build',
-        min: 0,
-        max: 1,
-      }),
-      with_raw_data: generateConfig({
-        label: 'with_raw_data',
-        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[] = [];
+  const getMetricDescription = (type: string) => {
+    return indexTrans(`metricType.${type}.description`);
+  };
 
 
-    indexParams.forEach(param => {
-      if (paramsMap.hasOwnProperty(param)) {
-        result.push(paramsMap[param as keyof typeof paramsMap]);
-      }
-    });
+  const paramConfigs = useMemo(() => {
+    const config = INDEX_PARAMS_CONFIG[fieldType]?.[formValue.index_type];
+    if (!config) return [];
 
 
-    return result;
-  }, [updateForm, warningTrans, indexParams, formValue]);
-
-  const indexNameConfig: ITextfieldConfig = {
-    label: indexTrans('indexName'),
-    key: 'index_name',
-    onChange: (value: string) => updateForm('index_name', value),
-    variant: 'filled',
-    fullWidth: true,
-    validations: [],
-    defaultValue: formValue.index_name,
-  };
+    const { required, optional, params } = config;
+    return [
+      ...required.map(key => ({ ...params[key], required: true })),
+      ...optional.filter(key => key && params[key]).map(key => params[key]),
+    ];
+  }, [fieldType, formValue.index_type]);
 
 
   return (
   return (
-    <div className={`${wrapperClass || ''}`} style={{ maxWidth: 480 }}>
-      <CustomGroupedSelect
-        label={indexTrans('type')}
-        options={indexOptions}
-        value={formValue.index_type}
-        onChange={(e: { target: { value: unknown } }) => {
-          const type = e.target.value;
-          updateForm('index_type', type as string);
-          // reset metric type value
-          if (metricOptions[0]) {
-            updateForm('metric_type', metricOptions[0].value as string);
-          }
-          indexTypeChange && indexTypeChange(type as string);
-        }}
-        style={{ width: '100%', marginBottom: theme.spacing(2) }}
-      />
-      <CustomInput
-        type="text"
-        textConfig={indexNameConfig}
-        checkValid={checkIsValid}
-        validInfo={validation}
-      />
-      {metricOptions.length ? (
-        <Typography
-          style={{
-            margin: theme.spacing(2, 0),
-            color: theme.palette.text.secondary,
-            lineHeight: '20px',
-            fontSize: 14,
+    <Box
+      className={wrapperClass || ''}
+      sx={{
+        maxWidth: 480,
+        display: 'flex',
+        flexDirection: 'column',
+        gap: 2,
+      }}
+    >
+      <FormControl variant="filled" fullWidth>
+        <InputLabel>{indexTrans('type')}</InputLabel>
+        <Select
+          value={formValue.index_type}
+          onChange={e => {
+            const type = e.target.value;
+            updateForm('index_type', type as string);
+            if (metricOptions[0]) {
+              updateForm('metric_type', metricOptions[0].value as string);
+            }
+            indexTypeChange && indexTypeChange(type as string);
           }}
           }}
+          label={indexTrans('type')}
         >
         >
-          {commonTrans('param')}
-        </Typography>
-      ) : null}
+          {indexOptions.map((group, groupIndex) => [
+            <ListSubheader
+              key={`${group.label}-header-${groupIndex}`}
+              sx={{
+                backgroundColor:
+                  theme.palette.mode === 'dark'
+                    ? theme.palette.grey[900]
+                    : theme.palette.grey[100],
+                color:
+                  theme.palette.mode === 'dark'
+                    ? theme.palette.common.white
+                    : theme.palette.text.primary,
+                fontWeight: 600,
+                fontSize: '13px',
+                lineHeight: '20px',
+                padding: '6px 16px',
+                textTransform: 'uppercase',
+                letterSpacing: '0.5px',
+                '&:hover': {
+                  backgroundColor:
+                    theme.palette.mode === 'dark'
+                      ? theme.palette.grey[900]
+                      : theme.palette.grey[100],
+                },
+              }}
+            >
+              {group.label}
+            </ListSubheader>,
+            ...(group.children || []).map((option: Option) => (
+              <MenuItem
+                key={`${group.label}-${option.value}-${groupIndex}`}
+                value={option.value}
+                sx={{
+                  padding: '8px 16px',
+                  fontSize: '14px',
+                  lineHeight: '20px',
+                  color: theme.palette.text.primary,
+                  '&:hover': {
+                    backgroundColor: theme.palette.action.hover,
+                  },
+                }}
+              >
+                {option.label}
+              </MenuItem>
+            )),
+          ])}
+        </Select>
+      </FormControl>
 
 
-      {metricOptions.length ? (
-        <CustomSelector
-          label={indexTrans('metric')}
-          value={formValue.metric_type}
-          options={metricOptions}
-          onChange={(e: { target: { value: unknown } }) => {
-            const type = e.target.value;
-            updateForm('metric_type', type as string);
-          }}
-          variant="filled"
-          wrapperClass=""
-          style={{ width: '100%', marginBottom: theme.spacing(2) }}
-        />
-      ) : null}
+      <TextField
+        fullWidth
+        variant="filled"
+        label={indexTrans('indexName')}
+        value={formValue.index_name}
+        onChange={e => updateForm('index_name', e.target.value)}
+        error={!!validation?.index_name}
+        helperText={''}
+        inputProps={{
+          pattern: '^[a-zA-Z_].*',
+          title: 'Index name must start with a letter or underscore',
+        }}
+        InputLabelProps={{
+          shrink: true,
+        }}
+      />
 
 
-      {paramsConfig.length
-        ? paramsConfig.map(v => (
-            <CustomInput
-              type="text"
-              textConfig={v}
-              checkValid={checkIsValid}
-              validInfo={validation}
-              key={v.label}
+      {metricOptions.length > 0 && (
+        <FormControl variant="filled" fullWidth>
+          <InputLabel>{indexTrans('metric')}</InputLabel>
+          <Select
+            value={formValue.metric_type}
+            onChange={e => {
+              updateForm('metric_type', e.target.value as string);
+            }}
+            label={indexTrans('metric')}
+          >
+            {metricOptions.map(option => (
+              <MenuItem key={option.value} value={option.value}>
+                {option.label}
+              </MenuItem>
+            ))}
+          </Select>
+          <FormHelperText>
+            {getMetricDescription(formValue.metric_type)}
+          </FormHelperText>
+        </FormControl>
+      )}
+
+      {paramConfigs.length > 0 && (
+        <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
+          {paramConfigs.map(config => (
+            <IndexParamField
+              key={config.key}
+              config={config}
+              value={formValue[config.key] || config.defaultValue || ''}
+              onChange={updateForm}
+              error={''}
             />
             />
-          ))
-        : null}
-    </div>
+          ))}
+        </Box>
+      )}
+    </Box>
   );
   );
 };
 };
+
 export default CreateForm;
 export default CreateForm;

+ 189 - 83
client/src/pages/databases/collections/schema/CreateIndexDialog.tsx

@@ -3,7 +3,6 @@ import { useTranslation } from 'react-i18next';
 import DialogTemplate from '@/components/customDialog/DialogTemplate';
 import DialogTemplate from '@/components/customDialog/DialogTemplate';
 import { Option } from '@/components/customSelector/Types';
 import { Option } from '@/components/customSelector/Types';
 import {
 import {
-  INDEX_CONFIG,
   INDEX_OPTIONS_MAP,
   INDEX_OPTIONS_MAP,
   METRIC_TYPES_VALUES,
   METRIC_TYPES_VALUES,
   INDEX_TYPES_ENUM,
   INDEX_TYPES_ENUM,
@@ -16,11 +15,17 @@ import {
   getMetricOptions,
   getMetricOptions,
   getScalarIndexOption,
   getScalarIndexOption,
   isVectorType,
   isVectorType,
+  formatFieldType,
 } from '@/utils';
 } from '@/utils';
 import CreateForm from './CreateForm';
 import CreateForm from './CreateForm';
 import type { IndexType, IndexExtraParam } from './Types';
 import type { IndexType, IndexExtraParam } from './Types';
 import type { FieldObject } from '@server/types';
 import type { FieldObject } from '@server/types';
+import { INDEX_PARAMS_CONFIG } from './indexParamsConfig';
 
 
+/**
+ * CreateIndex component for creating new indexes
+ * Handles index type selection, parameter configuration, and validation
+ */
 const CreateIndex = (props: {
 const CreateIndex = (props: {
   collectionName: string;
   collectionName: string;
   field: FieldObject;
   field: FieldObject;
@@ -33,9 +38,31 @@ const CreateIndex = (props: {
   const { t: dialogTrans } = useTranslation('dialog');
   const { t: dialogTrans } = useTranslation('dialog');
   const { t: btnTrans } = useTranslation('btn');
   const { t: btnTrans } = useTranslation('btn');
 
 
-  // https://milvus.io/docs/index.md#In-memory-Index
+  /**
+   * Convert field data type to DataTypeEnum
+   * Used to determine which index types and parameters are available
+   */
+  const getFieldType = (): DataTypeEnum => {
+    switch (field.data_type) {
+      case DataTypeStringEnum.BinaryVector:
+        return DataTypeEnum.BinaryVector;
+      case DataTypeStringEnum.FloatVector:
+      case DataTypeStringEnum.Float16Vector:
+      case DataTypeStringEnum.BFloat16Vector:
+        return DataTypeEnum.FloatVector;
+      case DataTypeStringEnum.SparseFloatVector:
+        return DataTypeEnum.SparseFloatVector;
+      default:
+        return DataTypeEnum.FloatVector;
+    }
+  };
+
   const defaultIndexType = INDEX_TYPES_ENUM.AUTOINDEX;
   const defaultIndexType = INDEX_TYPES_ENUM.AUTOINDEX;
 
 
+  /**
+   * Get default metric type based on field data type
+   * Different vector types have different default metric types
+   */
   const defaultMetricType = useMemo(() => {
   const defaultMetricType = useMemo(() => {
     switch (field.data_type) {
     switch (field.data_type) {
       case DataTypeStringEnum.BinaryVector:
       case DataTypeStringEnum.BinaryVector:
@@ -53,65 +80,72 @@ const CreateIndex = (props: {
     }
     }
   }, [field.data_type]);
   }, [field.data_type]);
 
 
+  // Form state for index creation
   const [indexSetting, setIndexSetting] = useState<{
   const [indexSetting, setIndexSetting] = useState<{
     index_type: IndexType;
     index_type: IndexType;
-    [x: string]: string;
+    [x: string]: string | number | boolean;
   }>({
   }>({
     index_name: '',
     index_name: '',
     index_type: defaultIndexType,
     index_type: defaultIndexType,
     metric_type: defaultMetricType,
     metric_type: defaultMetricType,
-    M: '',
-    m: '4',
-    efConstruction: '',
-    nlist: '',
-    nbits: '8',
-    n_trees: '',
-    outDegree: '',
-    candidatePoolSize: '',
-    searchLength: '',
-    knng: '',
-    drop_ratio_build: '0.32',
-    with_raw_data: 'true',
-    intermediate_graph_degree: '128',
-    graph_degree: '64',
-    build_algo: 'IVF_PQ',
-    cache_dataset_on_device: 'false',
   });
   });
 
 
+  /**
+   * Get required and optional parameters for the selected index type
+   * Parameters are defined in INDEX_PARAMS_CONFIG
+   */
   const indexCreateParams = useMemo(() => {
   const indexCreateParams = useMemo(() => {
-    if (!INDEX_CONFIG[indexSetting.index_type]) {
-      return [];
-    }
-    return INDEX_CONFIG[indexSetting.index_type].create;
+    const fieldType = getFieldType();
+    const config = INDEX_PARAMS_CONFIG[fieldType]?.[indexSetting.index_type];
+    if (!config) return [];
+    return [...config.required, ...config.optional];
   }, [indexSetting.index_type]);
   }, [indexSetting.index_type]);
 
 
+  /**
+   * Get available metric types for the selected index type
+   * Different index types support different metric types
+   */
   const metricOptions = useMemo(() => {
   const metricOptions = useMemo(() => {
     return isVectorType(field)
     return isVectorType(field)
       ? getMetricOptions(indexSetting.index_type, field)
       ? getMetricOptions(indexSetting.index_type, field)
       : [];
       : [];
   }, [indexSetting.index_type, field]);
   }, [indexSetting.index_type, field]);
 
 
+  /**
+   * Prepare parameters for index creation
+   * Combines index type, metric type, and other parameters
+   */
   const extraParams = useMemo(() => {
   const extraParams = useMemo(() => {
-    const params: { [x: string]: string } = {};
+    const params: { [x: string]: string | number | boolean } = {};
     indexCreateParams.forEach(v => {
     indexCreateParams.forEach(v => {
       params[v] = indexSetting[v];
       params[v] = indexSetting[v];
     });
     });
 
 
     const { index_type, metric_type } = indexSetting;
     const { index_type, metric_type } = indexSetting;
 
 
-    const extraParams: IndexExtraParam = {
+    return {
       index_type,
       index_type,
-      metric_type,
+      metric_type: String(metric_type),
       params: JSON.stringify(params),
       params: JSON.stringify(params),
     };
     };
-
-    return extraParams;
   }, [indexCreateParams, indexSetting]);
   }, [indexCreateParams, indexSetting]);
 
 
-  const getOptions = (label: string, children: Option[]) => [
-    { label, children },
-  ];
+  /**
+   * Helper function to format index options for the selector
+   * Groups options by category (in-memory, disk, GPU)
+   */
+  const getOptions = (label: string, children: Option[]) => ({
+    label,
+    children: children.map(child => ({
+      ...child,
+      key: `${label}-${child.value}`,
+    })),
+  });
 
 
+  /**
+   * Get available index types based on field type
+   * Different field types have different available index types
+   */
   const indexOptions = useMemo(() => {
   const indexOptions = useMemo(() => {
     const autoOption = getOptions('AUTOINDEX', INDEX_OPTIONS_MAP['AUTOINDEX']);
     const autoOption = getOptions('AUTOINDEX', INDEX_OPTIONS_MAP['AUTOINDEX']);
     let options = [];
     let options = [];
@@ -120,7 +154,7 @@ const CreateIndex = (props: {
       switch (field.data_type) {
       switch (field.data_type) {
         case DataTypeStringEnum.BinaryVector:
         case DataTypeStringEnum.BinaryVector:
           options = [
           options = [
-            ...getOptions(
+            getOptions(
               indexTrans('inMemory'),
               indexTrans('inMemory'),
               INDEX_OPTIONS_MAP[DataTypeEnum.BinaryVector]
               INDEX_OPTIONS_MAP[DataTypeEnum.BinaryVector]
             ),
             ),
@@ -129,7 +163,7 @@ const CreateIndex = (props: {
 
 
         case DataTypeStringEnum.SparseFloatVector:
         case DataTypeStringEnum.SparseFloatVector:
           options = [
           options = [
-            ...getOptions(
+            getOptions(
               indexTrans('inMemory'),
               indexTrans('inMemory'),
               INDEX_OPTIONS_MAP[DataTypeEnum.SparseFloatVector]
               INDEX_OPTIONS_MAP[DataTypeEnum.SparseFloatVector]
             ),
             ),
@@ -138,24 +172,45 @@ const CreateIndex = (props: {
 
 
         default:
         default:
           options = [
           options = [
-            ...getOptions(
+            getOptions(
               indexTrans('inMemory'),
               indexTrans('inMemory'),
-              INDEX_OPTIONS_MAP[DataTypeEnum.FloatVector]
+              INDEX_OPTIONS_MAP[DataTypeEnum.FloatVector].filter(
+                option =>
+                  option.value !== INDEX_TYPES_ENUM.DISKANN &&
+                  option.value !== INDEX_TYPES_ENUM.GPU_CAGRA &&
+                  option.value !== INDEX_TYPES_ENUM.GPU_IVF_FLAT &&
+                  option.value !== INDEX_TYPES_ENUM.GPU_IVF_PQ
+              )
+            ),
+            getOptions(
+              indexTrans('disk'),
+              INDEX_OPTIONS_MAP[DataTypeEnum.FloatVector].filter(
+                option => option.value === INDEX_TYPES_ENUM.DISKANN
+              )
+            ),
+            getOptions(
+              indexTrans('gpu'),
+              INDEX_OPTIONS_MAP[DataTypeEnum.FloatVector].filter(
+                option =>
+                  option.value === INDEX_TYPES_ENUM.GPU_CAGRA ||
+                  option.value === INDEX_TYPES_ENUM.GPU_IVF_FLAT ||
+                  option.value === INDEX_TYPES_ENUM.GPU_IVF_PQ
+              )
             ),
             ),
-            ...getOptions(indexTrans('disk'), INDEX_OPTIONS_MAP['DISK']),
-            ...getOptions(indexTrans('gpu'), INDEX_OPTIONS_MAP['GPU']),
           ];
           ];
           break;
           break;
       }
       }
     } else {
     } else {
-      options = [
-        ...getOptions(indexTrans('scalar'), getScalarIndexOption(field)),
-      ];
+      options = [getOptions(indexTrans('scalar'), getScalarIndexOption(field))];
     }
     }
 
 
-    return [...autoOption, ...options];
-  }, [field]);
+    return [autoOption, ...options];
+  }, [field, indexTrans]);
 
 
+  /**
+   * Format form data for validation
+   * Combines metric type and index parameters
+   */
   const checkedForm = useMemo(() => {
   const checkedForm = useMemo(() => {
     if (!isVectorType(field)) {
     if (!isVectorType(field)) {
       return [];
       return [];
@@ -164,68 +219,119 @@ const CreateIndex = (props: {
     indexCreateParams.forEach(v => {
     indexCreateParams.forEach(v => {
       paramsForm[v] = indexSetting[v];
       paramsForm[v] = indexSetting[v];
     });
     });
-    const form = formatForm(paramsForm);
-    return form;
+    return formatForm(paramsForm);
   }, [indexSetting, indexCreateParams, field]);
   }, [indexSetting, indexCreateParams, field]);
 
 
-  const {
-    validation,
-    checkIsValid,
-    disabled,
-    resetValidation,
-    checkFormValid,
-  } = useFormValidation(checkedForm);
+  const { validation, checkIsValid, resetValidation } =
+    useFormValidation(checkedForm);
 
 
-  const updateStepTwoForm = (type: string, value: string) => {
+  /**
+   * Check if form is valid
+   * Validates required parameters and their values
+   */
+  const isFormValid = useMemo(() => {
+    const fieldType = getFieldType();
+    const config = INDEX_PARAMS_CONFIG[fieldType]?.[indexSetting.index_type];
+    if (!config) return true;
+
+    const hasAllRequiredParams = config.required.every(param => {
+      const value = indexSetting[param];
+      return value !== undefined && value !== '';
+    });
+
+    const validationErrors = Object.entries(validation || {}).filter(
+      ([key, error]) => {
+        if (!config.required.includes(key) && !indexSetting[key]) {
+          return false;
+        }
+        return (
+          error &&
+          typeof error === 'object' &&
+          'errText' in error &&
+          error.errText
+        );
+      }
+    );
+
+    return hasAllRequiredParams && validationErrors.length === 0;
+  }, [indexSetting, validation]);
+
+  /**
+   * Update form field value
+   */
+  const updateForm = (type: string, value: string | number | boolean) => {
     setIndexSetting(v => ({ ...v, [type]: value }));
     setIndexSetting(v => ({ ...v, [type]: value }));
   };
   };
 
 
+  /**
+   * Handle index type change
+   * Reset parameters when index type changes and set default values from config
+   */
   const onIndexTypeChange = (type: string) => {
   const onIndexTypeChange = (type: string) => {
-    // reset index params
-    let paramsForm: { [key in string]: string } = {};
-    // m is selector not input
-    ((INDEX_CONFIG[type] && INDEX_CONFIG[type].create) || [])
-      .filter(t => t !== 'm')
-      .forEach(item => {
-        paramsForm[item] = '';
-      });
-    // if no other params, the form should be valid.
-    const form = formatForm(paramsForm);
-    resetValidation(form);
-    // trigger validation check after the render
-    setTimeout(() => {
-      checkFormValid('.index-form .MuiInputBase-input');
-    }, 0);
+    const fieldType = getFieldType();
+    const config = INDEX_PARAMS_CONFIG[fieldType]?.[type];
+    if (!config) return;
+
+    // Create new form state with default values
+    const newIndexSetting: {
+      index_type: IndexType;
+      [key: string]: string | number | boolean;
+    } = {
+      ...indexSetting,
+      index_type: type as IndexType,
+    };
+
+    // Set default values for all parameters from config
+    Object.entries(config.params).forEach(([key, paramConfig]) => {
+      if (paramConfig.defaultValue !== undefined) {
+        newIndexSetting[key] = paramConfig.defaultValue.toString();
+      } else {
+        newIndexSetting[key] = '';
+      }
+    });
+
+    // Update form state
+    setIndexSetting(newIndexSetting);
+
+    // Reset validation with new values
+    const paramsForm: { [key: string]: string | number | boolean } = {};
+    [...config.required, ...config.optional].forEach(param => {
+      paramsForm[param] = newIndexSetting[param];
+    });
+
+    resetValidation(formatForm(paramsForm));
   };
   };
 
 
+  /**
+   * Handle index creation
+   */
   const handleCreateIndex = async () => {
   const handleCreateIndex = async () => {
-    await handleCreate(extraParams, indexSetting.index_name);
+    await handleCreate(extraParams, indexSetting.index_name as string);
   };
   };
 
 
   return (
   return (
     <DialogTemplate
     <DialogTemplate
       title={dialogTrans('createTitle', {
       title={dialogTrans('createTitle', {
         type: indexTrans('index'),
         type: indexTrans('index'),
-        name: field.name,
+        name: `${field.name} - ${formatFieldType(field)}`,
       })}
       })}
       handleClose={handleCancel}
       handleClose={handleCancel}
       confirmLabel={btnTrans('create')}
       confirmLabel={btnTrans('create')}
       handleConfirm={handleCreateIndex}
       handleConfirm={handleCreateIndex}
-      confirmDisabled={disabled}
+      confirmDisabled={!isFormValid}
     >
     >
-      <>
-        <CreateForm
-          updateForm={updateStepTwoForm}
-          metricOptions={metricOptions}
-          indexOptions={indexOptions}
-          formValue={indexSetting}
-          checkIsValid={checkIsValid}
-          validation={validation}
-          indexParams={indexCreateParams}
-          indexTypeChange={onIndexTypeChange}
-          wrapperClass="index-form"
-        />
-      </>
+      <CreateForm
+        updateForm={updateForm}
+        metricOptions={metricOptions}
+        indexOptions={indexOptions}
+        formValue={indexSetting}
+        checkIsValid={checkIsValid}
+        validation={validation}
+        indexParams={indexCreateParams}
+        indexTypeChange={onIndexTypeChange}
+        wrapperClass="index-form"
+        fieldType={getFieldType()}
+      />
     </DialogTemplate>
     </DialogTemplate>
   );
   );
 };
 };

+ 114 - 0
client/src/pages/databases/collections/schema/IndexParamField.tsx

@@ -0,0 +1,114 @@
+import {
+  TextField,
+  Switch,
+  FormControlLabel,
+  FormHelperText,
+  Box,
+} from '@mui/material';
+import { useTranslation } from 'react-i18next';
+import type { IndexParamConfig } from './indexParamsConfig';
+
+interface IndexParamFieldProps {
+  config: IndexParamConfig;
+  value: string | number | boolean;
+  onChange: (key: string, value: string | number | boolean) => void;
+  error?: string;
+}
+
+const IndexParamField = ({
+  config,
+  value,
+  onChange,
+  error,
+}: IndexParamFieldProps) => {
+  const { t: indexTrans } = useTranslation('index');
+
+  const renderField = () => {
+    switch (config.type) {
+      case 'bool':
+        return (
+          <FormControlLabel
+            control={
+              <Switch
+                checked={typeof value === 'boolean' ? value : value === 'true'}
+                onChange={e => onChange(config.key, e.target.checked)}
+                color="primary"
+              />
+            }
+            label={config.label}
+          />
+        );
+      case 'number':
+        return (
+          <TextField
+            fullWidth
+            variant="filled"
+            label={config.label}
+            type="number"
+            value={typeof value === 'number' ? value : value || ''}
+            onChange={e => {
+              const val = e.target.value;
+              if (val === '') {
+                onChange(config.key, '');
+              } else {
+                const num = Number(val);
+                if (!isNaN(num)) {
+                  onChange(config.key, num);
+                }
+              }
+            }}
+            error={!!error}
+            helperText={error}
+            inputProps={{
+              min: config.min,
+              max: config.max,
+            }}
+            InputLabelProps={{
+              shrink: true,
+            }}
+            required={config.required}
+          />
+        );
+      default:
+        return (
+          <TextField
+            fullWidth
+            variant="filled"
+            label={config.label}
+            value={value || ''}
+            onChange={e => onChange(config.key, e.target.value)}
+            error={!!error}
+            helperText={error}
+            InputLabelProps={{
+              shrink: true,
+            }}
+            required={config.required}
+          />
+        );
+    }
+  };
+
+  return (
+    <Box sx={{ mb: 0 }}>
+      {renderField()}
+      {(config.helperText || error) && (
+        <FormHelperText
+          error={!!error}
+          sx={{
+            mt: 0.5,
+            mb: 0,
+            fontSize: '0.75rem',
+            lineHeight: 1.2,
+          }}
+        >
+          {!error && config.description && (
+            <>{indexTrans(config.description)}&nbsp;</>
+          )}
+          {error || (config.helperText ? indexTrans(config.helperText) : '')}
+        </FormHelperText>
+      )}
+    </Box>
+  );
+};
+
+export default IndexParamField;

+ 6 - 4
client/src/pages/databases/collections/schema/Types.ts

@@ -14,12 +14,14 @@ export type IndexType =
   | INDEX_TYPES_ENUM.HNSW
   | INDEX_TYPES_ENUM.HNSW
   | INDEX_TYPES_ENUM.BIN_IVF_FLAT
   | INDEX_TYPES_ENUM.BIN_IVF_FLAT
   | INDEX_TYPES_ENUM.BIN_FLAT
   | INDEX_TYPES_ENUM.BIN_FLAT
-  | INDEX_TYPES_ENUM.MARISA_TRIE
-  | INDEX_TYPES_ENUM.SORT
+  | INDEX_TYPES_ENUM.Trie
+  | INDEX_TYPES_ENUM.STL_SORT
   | INDEX_TYPES_ENUM.AUTOINDEX
   | INDEX_TYPES_ENUM.AUTOINDEX
   | INDEX_TYPES_ENUM.SPARSE_INVERTED_INDEX
   | INDEX_TYPES_ENUM.SPARSE_INVERTED_INDEX
-  | INDEX_TYPES_ENUM.SPARSE_WAND
-  | INDEX_TYPES_ENUM.INVERTED;
+  | INDEX_TYPES_ENUM.INVERTED
+  | INDEX_TYPES_ENUM.HNSW_SQ
+  | INDEX_TYPES_ENUM.HNSW_PQ
+  | INDEX_TYPES_ENUM.HNSW_PRQ;
 
 
 export interface IndexManageParam {
 export interface IndexManageParam {
   collection_name: string;
   collection_name: string;

+ 457 - 0
client/src/pages/databases/collections/schema/indexParamsConfig.ts

@@ -0,0 +1,457 @@
+import { DataTypeEnum, INDEX_TYPES_ENUM } from '@/consts';
+
+export interface IndexParamConfig {
+  label: string;
+  key: string;
+  type: 'number' | 'text' | 'bool';
+  required?: boolean;
+  min?: number;
+  max?: number;
+  defaultValue?: string | number | boolean;
+  description?: string;
+  helperText?: string;
+}
+
+export interface IndexTypeConfig {
+  required: string[];
+  optional: string[];
+  params: Record<string, IndexParamConfig>;
+  searchParams?: Record<string, IndexParamConfig>;
+}
+
+// Common parameter configurations
+const commonParams = {
+  nlist: {
+    label: 'nlist',
+    key: 'nlist',
+    type: 'number' as const,
+    required: true,
+    min: 1,
+    max: 65536,
+    defaultValue: '128',
+    description: 'params.nlist.description',
+    helperText: 'params.nlist.helperText',
+  },
+  M: {
+    label: 'M',
+    key: 'M',
+    type: 'number' as const,
+    required: true,
+    min: 2,
+    max: 2048,
+    description: 'params.M.description',
+    helperText: 'params.M.helperText',
+  },
+  efConstruction: {
+    label: 'efConstruction',
+    key: 'efConstruction',
+    type: 'number' as const,
+    required: true,
+    min: 1,
+    max: 2147483647,
+    description: 'params.efConstruction.description',
+    helperText: 'params.efConstruction.helperText',
+  },
+  refine: {
+    label: 'refine',
+    key: 'refine',
+    type: 'bool' as const,
+    defaultValue: 'false',
+    description: 'params.refine.description',
+    helperText: 'params.refine.helperText',
+  },
+  refine_type: {
+    label: 'refine_type',
+    key: 'refine_type',
+    type: 'text' as const,
+    description: 'params.refine_type.description',
+    helperText: 'params.refine_type.helperText',
+  },
+  m: {
+    label: 'm',
+    key: 'm',
+    type: 'number' as const,
+    required: true,
+    min: 1,
+    max: 65536,
+    defaultValue: '32',
+    description: 'params.m.description',
+    helperText: 'params.m.helperText',
+  },
+  nbits: {
+    label: 'nbits',
+    key: 'nbits',
+    type: 'number' as const,
+    min: 1,
+    max: 24,
+    defaultValue: '8',
+    description: 'params.nbits.description',
+    helperText: 'params.nbits.helperText.common',
+  },
+  cache_dataset_on_device: {
+    label: 'cache_dataset_on_device',
+    key: 'cache_dataset_on_device',
+    type: 'bool' as const,
+    defaultValue: 'false',
+    description: 'params.cache_dataset_on_device.description',
+    helperText: 'params.cache_dataset_on_device.helperText',
+  },
+};
+
+// Common search parameter configurations
+const commonSearchParams = {
+  nprobe: {
+    label: 'nprobe',
+    key: 'nprobe',
+    type: 'number' as const,
+    required: false,
+    min: 1,
+    max: 65536,
+    defaultValue: '8',
+    description: 'searchParams.nprobe.description',
+    helperText: 'searchParams.nprobe.helperText',
+  },
+  max_empty_result_buckets: {
+    label: 'max_empty_result_buckets',
+    key: 'max_empty_result_buckets',
+    type: 'number' as const,
+    required: false,
+    min: 1,
+    max: 65535,
+    defaultValue: '2',
+    description: 'searchParams.max_empty_result_buckets.description',
+    helperText: 'searchParams.max_empty_result_buckets.helperText',
+  },
+  ef: {
+    label: 'ef',
+    key: 'ef',
+    type: 'number' as const,
+    required: false,
+    min: 1,
+    max: 2147483647,
+    description: 'searchParams.efConstruction.description',
+    helperText: 'searchParams.efConstruction.helperText',
+  },
+  refine_k: {
+    label: 'refine_k',
+    key: 'refine_k',
+    type: 'number' as const,
+    required: false,
+    min: 1,
+    max: 2147483647,
+    defaultValue: '1',
+    description: 'searchParams.refine_k.description',
+    helperText: 'searchParams.refine_k.helperText',
+  },
+};
+
+export const INDEX_PARAMS_CONFIG: Record<
+  string,
+  Record<string, IndexTypeConfig>
+> = {
+  [DataTypeEnum.FloatVector]: {
+    [INDEX_TYPES_ENUM.IVF_FLAT]: {
+      required: ['nlist'],
+      optional: ['nbits'],
+      params: {
+        nlist: commonParams.nlist,
+      },
+      searchParams: {
+        nprobe: commonSearchParams.nprobe,
+        max_empty_result_buckets: commonSearchParams.max_empty_result_buckets,
+      },
+    },
+    [INDEX_TYPES_ENUM.HNSW]: {
+      required: ['M', 'efConstruction'],
+      optional: [''],
+      params: {
+        M: commonParams.M,
+        efConstruction: commonParams.efConstruction,
+      },
+      searchParams: {
+        ef: commonSearchParams.ef,
+      },
+    },
+    [INDEX_TYPES_ENUM.IVF_SQ8]: {
+      required: ['nlist'],
+      optional: [''],
+      params: {
+        nlist: commonParams.nlist,
+      },
+      searchParams: {
+        nprobe: commonSearchParams.nprobe,
+        max_empty_result_buckets: commonSearchParams.max_empty_result_buckets,
+      },
+    },
+    [INDEX_TYPES_ENUM.IVF_PQ]: {
+      required: ['nlist', 'm'],
+      optional: ['nbits'],
+      params: {
+        nlist: commonParams.nlist,
+        m: commonParams.m,
+        nbits: {
+          ...commonParams.nbits,
+          max: 64,
+          helperText: 'params.nbits.helperText.IVF_PQ',
+        },
+      },
+      searchParams: {
+        nprobe: commonSearchParams.nprobe,
+        max_empty_result_buckets: commonSearchParams.max_empty_result_buckets,
+      },
+    },
+    SCANN: {
+      required: ['nlist'],
+      optional: ['with_raw_data'],
+      params: {
+        nlist: commonParams.nlist,
+        with_raw_data: {
+          label: 'with_raw_data',
+          key: 'with_raw_data',
+          type: 'bool' as const,
+          defaultValue: 'true',
+          description: 'params.with_raw_data.description',
+        },
+      },
+      searchParams: {
+        nprobe: commonSearchParams.nprobe,
+        reorder_k: {
+          label: 'reorder_k',
+          key: 'reorder_k',
+          type: 'number' as const,
+          required: false,
+          defaultValue: '',
+          description: 'searchParams.reorder_k.description',
+          helperText: 'searchParams.reorder_k.helperText',
+        },
+      },
+    },
+    [INDEX_TYPES_ENUM.HNSW_SQ]: {
+      required: ['M', 'efConstruction', 'sq_type'],
+      optional: ['refine'],
+      params: {
+        M: commonParams.M,
+        efConstruction: commonParams.efConstruction,
+        sq_type: {
+          label: 'sq_type',
+          key: 'sq_type',
+          type: 'text' as const,
+          required: true,
+          defaultValue: 'SQ8',
+          description: 'params.sq_type.description',
+          helperText: 'params.sq_type.helperText',
+        },
+        refine: commonParams.refine,
+        refine_type: commonParams.refine_type,
+      },
+      searchParams: {
+        ef: commonSearchParams.ef,
+        refine_k: commonSearchParams.refine_k,
+      },
+    },
+    [INDEX_TYPES_ENUM.HNSW_PQ]: {
+      required: ['M', 'efConstruction', 'm', 'nbits'],
+      optional: ['refine'],
+      params: {
+        M: commonParams.M,
+        efConstruction: commonParams.efConstruction,
+        m: commonParams.m,
+        nbits: commonParams.nbits,
+        refine: commonParams.refine,
+        refine_type: commonParams.refine_type,
+      },
+      searchParams: {
+        ef: commonSearchParams.ef,
+        refine_k: commonSearchParams.refine_k,
+      },
+    },
+    [INDEX_TYPES_ENUM.HNSW_PRQ]: {
+      required: ['M', 'efConstruction', 'm', 'nbits', 'nrq'],
+      optional: ['refine'],
+      params: {
+        M: commonParams.M,
+        efConstruction: commonParams.efConstruction,
+        m: commonParams.m,
+        nbits: commonParams.nbits,
+        nrq: {
+          label: 'nrq',
+          key: 'nrq',
+          type: 'number' as const,
+          required: true,
+          min: 1,
+          max: 16,
+          defaultValue: '2',
+          description: 'params.nrq.description',
+          helperText: 'params.nrq.helperText',
+        },
+        refine: commonParams.refine,
+        refine_type: commonParams.refine_type,
+      },
+      searchParams: {
+        ef: commonSearchParams.ef,
+        refine_k: commonSearchParams.refine_k,
+      },
+    },
+    [INDEX_TYPES_ENUM.DISKANN]: {
+      required: [],
+      optional: [],
+      params: {},
+      searchParams: {
+        search_list: {
+          label: 'search_list',
+          key: 'search_list',
+          type: 'number' as const,
+          required: false,
+          defaultValue: '16',
+          description: 'searchParams.search_list.description',
+          helperText: 'searchParams.search_list.helperText',
+        },
+      },
+    },
+    [INDEX_TYPES_ENUM.GPU_CAGRA]: {
+      required: ['intermediate_graph_degree', 'graph_degree', 'build_algo'],
+      optional: ['cache_dataset_on_device', 'adapt_for_cpu'],
+      params: {
+        intermediate_graph_degree: {
+          label: 'intermediate_graph_degree',
+          key: 'intermediate_graph_degree',
+          type: 'number' as const,
+          required: true,
+          min: 1,
+          max: 1024,
+          defaultValue: '128',
+          description: 'params.intermediate_graph_degree.description',
+          helperText: 'params.intermediate_graph_degree.helperText',
+        },
+        graph_degree: {
+          label: 'graph_degree',
+          key: 'graph_degree',
+          type: 'number' as const,
+          required: true,
+          min: 1,
+          max: 1024,
+          defaultValue: '64',
+          description: 'params.graph_degree.description',
+          helperText: 'params.graph_degree.helperText',
+        },
+        build_algo: {
+          label: 'build_algo',
+          key: 'build_algo',
+          type: 'text' as const,
+          required: true,
+          defaultValue: 'IVF_PQ',
+          description: 'params.build_algo.description',
+          helperText: 'params.build_algo.helperText',
+        },
+        cache_dataset_on_device: commonParams.cache_dataset_on_device,
+        adapt_for_cpu: {
+          label: 'adapt_for_cpu',
+          key: 'adapt_for_cpu',
+          type: 'bool' as const,
+          defaultValue: 'false',
+          description: 'params.adapt_for_cpu.description',
+          helperText: 'params.adapt_for_cpu.helperText',
+        },
+      },
+      searchParams: {
+        itopk_size: {
+          label: 'itopk_size',
+          key: 'itopk_size',
+          type: 'number' as const,
+          required: false,
+          min: 1,
+          max: 2147483647,
+          defaultValue: '',
+          description: 'searchParams.itopk_size.description',
+          helperText: 'searchParams.itopk_size.helperText',
+        },
+        search_width: {
+          label: 'search_width',
+          key: 'search_width',
+          type: 'number' as const,
+          required: false,
+          min: 1,
+          max: 2147483647,
+          defaultValue: '',
+          description: 'searchParams.search_width.description',
+          helperText: 'searchParams.search_width.helperText',
+        },
+        min_iterations: {
+          label: 'min_iterations',
+          key: 'min_iterations',
+          type: 'number' as const,
+          required: false,
+          min: 0,
+          max: 2147483647,
+          defaultValue: '0',
+          description: 'searchParams.min_iterations.description',
+          helperText: 'searchParams.min_iterations.helperText',
+        },
+        max_iterations: {
+          label: 'max_iterations',
+          key: 'max_iterations',
+          type: 'number' as const,
+          required: false,
+          min: 0,
+          max: 2147483647,
+          defaultValue: '0',
+          description: 'searchParams.max_iterations.description',
+          helperText: 'searchParams.max_iterations.helperText',
+        },
+        team_size: {
+          label: 'team_size',
+          key: 'team_size',
+          type: 'number' as const,
+          required: false,
+          min: 0,
+          max: 32,
+          defaultValue: '0',
+          description: 'searchParams.team_size.description',
+          helperText: 'searchParams.team_size.helperText',
+        },
+        ef: commonSearchParams.ef,
+      },
+    },
+    [INDEX_TYPES_ENUM.GPU_IVF_FLAT]: {
+      required: ['nlist'],
+      optional: ['cache_dataset_on_device'],
+      params: {
+        nlist: commonParams.nlist,
+        cache_dataset_on_device: commonParams.cache_dataset_on_device,
+      },
+      searchParams: {
+        nprobe: commonSearchParams.nprobe,
+      },
+    },
+    [INDEX_TYPES_ENUM.GPU_IVF_PQ]: {
+      required: ['nlist', 'm'],
+      optional: ['nbits', 'cache_dataset_on_device'],
+      params: {
+        nlist: commonParams.nlist,
+        m: commonParams.m,
+        nbits: {
+          ...commonParams.nbits,
+          max: 16,
+          helperText: 'params.nbits.helperText.IVF_PQ',
+        },
+        cache_dataset_on_device: commonParams.cache_dataset_on_device,
+      },
+      searchParams: {
+        nprobe: commonSearchParams.nprobe,
+      },
+    },
+  },
+  [DataTypeEnum.BinaryVector]: {
+    [INDEX_TYPES_ENUM.BIN_IVF_FLAT]: {
+      required: ['nlist'],
+      optional: [],
+      params: {
+        nlist: commonParams.nlist,
+      },
+      searchParams: {
+        nprobe: commonSearchParams.nprobe,
+        max_empty_result_buckets: commonSearchParams.max_empty_result_buckets,
+      },
+    },
+  },
+};

+ 7 - 11
client/src/pages/databases/collections/search/Search.tsx

@@ -23,7 +23,7 @@ import {
   buildSearchParams,
   buildSearchParams,
   getColumnWidth,
   getColumnWidth,
 } from '@/utils';
 } from '@/utils';
-import SearchParams from '../../../search/SearchParams';
+import SearchParams from './SearchParams';
 import DataExplorer, { formatMilvusData } from './DataExplorer';
 import DataExplorer, { formatMilvusData } from './DataExplorer';
 import {
 import {
   SearchParams as SearchParamsType,
   SearchParams as SearchParamsType,
@@ -447,7 +447,10 @@ const Search = (props: CollectionDataProps) => {
                         </Typography>
                         </Typography>
                         <Typography className="vector-type">
                         <Typography className="vector-type">
                           {formatFieldType(field)}
                           {formatFieldType(field)}
-                          <i>{field.index && field.index.metricType}</i>
+                          <i>
+                            {field.index &&
+                              `${field.index.indexType}(${field.index.metricType})`}
+                          </i>
                         </Typography>
                         </Typography>
                       </div>
                       </div>
                     </CheckboxRow>
                     </CheckboxRow>
@@ -461,21 +464,14 @@ const Search = (props: CollectionDataProps) => {
                     />
                     />
 
 
                     <SearchParams
                     <SearchParams
-                      sx={{ pt: 1 }}
-                      consistency_level={'Strong'}
-                      handleConsistencyChange={(level: string) => {}}
+                      sx={{ pt: 1, mb: 1 }}
                       indexType={field.index.indexType}
                       indexType={field.index.indexType}
-                      indexParams={field.index_params}
                       searchParamsForm={s.params}
                       searchParamsForm={s.params}
                       handleFormChange={(updates: {
                       handleFormChange={(updates: {
-                        [key in string]: number | string;
+                        [key in string]: number | string | boolean;
                       }) => {
                       }) => {
                         updateSearchParamCallback(updates as any, index);
                         updateSearchParamCallback(updates as any, index);
                       }}
                       }}
-                      topK={searchParams.globalParams.topK}
-                      setParamsDisabled={() => {
-                        return false;
-                      }}
                     />
                     />
                   </StyledAccordionDetails>
                   </StyledAccordionDetails>
                 </StyledAccordion>
                 </StyledAccordion>

+ 132 - 0
client/src/pages/databases/collections/search/SearchParams.tsx

@@ -0,0 +1,132 @@
+import { FC, useCallback, useMemo } from 'react';
+import Box from '@mui/material/Box';
+import { INDEX_PARAMS_CONFIG } from '@/pages/databases/collections/schema/indexParamsConfig';
+import IndexParamField from '@/pages/databases/collections/schema/IndexParamField';
+import type { SearchParamsProps } from './Types';
+import type { IndexParamConfig } from '@/pages/databases/collections/schema/indexParamsConfig';
+
+const COMMON_PARAMS = ['level', 'radius', 'range_filter'] as const;
+
+const SearchParams: FC<SearchParamsProps> = ({
+  indexType = '',
+  searchParamsForm,
+  handleFormChange,
+  sx = {},
+}) => {
+  // Get search params and their configs based on index type
+  const { paramList, paramConfigs } = useMemo(() => {
+    // Common params that are always available
+    const commonParams: Record<string, IndexParamConfig> = {
+      radius: {
+        label: 'radius',
+        key: 'radius',
+        type: 'number',
+        required: false,
+        // description: 'searchParams.radius.description',
+        // helperText: 'searchParams.radius.helperText',
+      },
+      range_filter: {
+        label: 'range filter',
+        key: 'range_filter',
+        type: 'number',
+        required: false,
+        // helperText: 'searchParams.range_filter.helperText',
+        // description: 'searchParams.range_filter.description',
+      },
+    };
+
+    if (indexType === 'AUTOINDEX') {
+      commonParams.level = {
+        label: 'level',
+        key: 'level',
+        type: 'number',
+        required: false,
+        min: 1,
+        max: 10,
+        defaultValue: '1',
+        helperText: 'searchParams.level.description',
+      };
+    }
+
+    // Get search params for the specific index type
+    const indexParams: Record<string, IndexParamConfig> = {};
+    Object.values(INDEX_PARAMS_CONFIG).forEach(dataTypeConfig => {
+      const config = dataTypeConfig[indexType];
+      if (config?.searchParams) {
+        Object.entries(config.searchParams).forEach(([param, paramConfig]) => {
+          indexParams[param] = paramConfig;
+        });
+      }
+    });
+
+    const allParams = { ...indexParams, ...commonParams };
+    const allParamKeys = Object.keys(allParams);
+
+    // Sort params to ensure common params are at the end
+    const sortedParamKeys = allParamKeys.sort((a, b) => {
+      const aIsCommon = COMMON_PARAMS.includes(
+        a as (typeof COMMON_PARAMS)[number]
+      );
+      const bIsCommon = COMMON_PARAMS.includes(
+        b as (typeof COMMON_PARAMS)[number]
+      );
+      if (aIsCommon && !bIsCommon) return 1;
+      if (!aIsCommon && bIsCommon) return -1;
+      if (aIsCommon && bIsCommon) {
+        return (
+          COMMON_PARAMS.indexOf(a as (typeof COMMON_PARAMS)[number]) -
+          COMMON_PARAMS.indexOf(b as (typeof COMMON_PARAMS)[number])
+        );
+      }
+      return 0;
+    });
+
+    return {
+      paramList: sortedParamKeys,
+      paramConfigs: allParams,
+    };
+  }, [indexType]);
+
+  const handleInputChange = useCallback(
+    (key: string, value: string | number | boolean) => {
+      let form = { ...searchParamsForm };
+      if (value === '') {
+        delete form[key];
+      } else {
+        form = { ...searchParamsForm, [key]: value };
+      }
+      handleFormChange(form);
+    },
+    [handleFormChange, searchParamsForm]
+  );
+
+  return (
+    <Box
+      sx={{
+        ...sx,
+        display: 'flex',
+        flexDirection: 'column',
+        gap: 2,
+      }}
+    >
+      {paramList.map(param => {
+        const config = paramConfigs[param];
+        if (!config) return null;
+
+        const value = searchParamsForm[param] ?? config.defaultValue ?? '';
+
+        return (
+          <IndexParamField
+            key={param}
+            config={config}
+            value={value}
+            onChange={handleInputChange}
+            error={''}
+          />
+        );
+      })}
+    </Box>
+  );
+};
+
+export default SearchParams;

+ 2 - 2
client/src/pages/databases/collections/search/StyledComponents.ts

@@ -17,7 +17,7 @@ export const InputArea = styled(Box)({
 
 
 export const AccordionsContainer = styled(Box)(({ theme }) => ({
 export const AccordionsContainer = styled(Box)(({ theme }) => ({
   display: 'flex',
   display: 'flex',
-  width: '230px',
+  width: '260px',
   flexDirection: 'column',
   flexDirection: 'column',
   flexShrink: 0,
   flexShrink: 0,
   padding: '0 8px 8px 0',
   padding: '0 8px 8px 0',
@@ -279,7 +279,7 @@ export const CheckboxRow = styled('div')(({ theme }) => ({
     lineHeight: '20px',
     lineHeight: '20px',
     '& i': {
     '& i': {
       marginLeft: '4px',
       marginLeft: '4px',
-      fontSize: '10px',
+      fontSize: '9px',
       fontWeight: 600,
       fontWeight: 600,
       color: theme.palette.secondary.main,
       color: theme.palette.secondary.main,
     },
     },

+ 32 - 0
client/src/pages/databases/collections/search/Types.ts

@@ -0,0 +1,32 @@
+import type { FieldObject } from '@server/types';
+import type { Option } from '@/components/customSelector/Types';
+import type { SxProps, Theme } from '@mui/material';
+
+export interface SearchParamsProps {
+  // default index type is FLAT
+  indexType?: string;
+  searchParamsForm: {
+    [key in string]: number | string | boolean;
+  };
+  handleFormChange: (form: {
+    [key in string]: number | string | boolean;
+  }) => void;
+  sx?: SxProps<Theme>;
+}
+
+export interface SearchResultView {
+  // dynamic field names
+  [key: string]: any;
+  rank: number;
+  distance: number;
+}
+
+export interface FieldOption extends Option {
+  field: FieldObject;
+}
+
+export interface SearchResult {
+  // dynamic field names
+  [key: string]: string | number;
+  score: number;
+}

+ 0 - 424
client/src/pages/search/SearchParams.tsx

@@ -1,424 +0,0 @@
-import { FC, useCallback, useContext, useEffect, useMemo } from 'react';
-import Box from '@mui/material/Box';
-import { useTranslation } from 'react-i18next';
-import CustomInput from '@/components/customInput/CustomInput';
-import { ITextfieldConfig } from '@/components/customInput/Types';
-import {
-  DEFAULT_NLIST_VALUE,
-  DEFAULT_SEARCH_PARAM_VALUE_MAP,
-  INDEX_CONFIG,
-  searchKeywordsType,
-} from '@/consts';
-import { rootContext } from '@/context';
-import { useFormValidation } from '@/hooks';
-import { formatForm } from '@/utils';
-import type { SearchParamInputConfig, SearchParamsProps } from './Types';
-
-const SearchParams: FC<SearchParamsProps> = ({
-  indexType = '',
-  indexParams = [],
-  searchParamsForm,
-  handleFormChange,
-  topK,
-  setParamsDisabled,
-  sx = {},
-}) => {
-  const { t: warningTrans } = useTranslation('warning');
-
-  const { openSnackBar } = useContext(rootContext);
-
-  // search params key list, depends on index type
-  // e.g. ['nprobe']
-  const searchParams = useMemo((): searchKeywordsType[] => {
-    const isSupportedType = Object.keys(INDEX_CONFIG).includes(indexType);
-
-    // show warning snackbar for unsupported type
-    if (!isSupportedType) {
-      indexType !== '' &&
-        openSnackBar(
-          warningTrans('noSupportIndexType', { type: indexType }),
-          'warning'
-        );
-    }
-
-    const commonParams: searchKeywordsType[] = ['radius', 'range_filter'];
-    return indexType !== '' && isSupportedType
-      ? [...INDEX_CONFIG[indexType!].search, ...commonParams]
-      : commonParams;
-  }, [indexType, openSnackBar, warningTrans]);
-
-  const handleInputChange = useCallback(
-    (key: string, value: number | string | typeof NaN) => {
-      let form = { ...searchParamsForm };
-      if (value === '' || isNaN(value as any)) {
-        delete form[key];
-      } else {
-        form = { ...searchParamsForm, [key]: value };
-      }
-
-      handleFormChange(form);
-    },
-    [handleFormChange, searchParamsForm]
-  );
-
-  /**
-   * function to transfer search params to CustomInput need config type
-   */
-  const getInputConfig = useCallback(
-    (params: SearchParamInputConfig): ITextfieldConfig => {
-      const {
-        label,
-        key,
-        min,
-        max,
-        value,
-        handleChange,
-        isInt = true,
-        type = 'number',
-        required = true,
-      } = params;
-
-      // search_k range is special compared to others,need to be handled separately
-      // range: {-1} ∪ [top_k, n × n_trees]
-      const isSearchK = label === 'search_k';
-
-      const config: ITextfieldConfig = {
-        label,
-        key,
-        onChange: value => {
-          handleChange(value);
-        },
-        className: 'inline-input',
-        variant: 'filled',
-        type: type,
-        value,
-        validations: [],
-      };
-
-      if (required) {
-        config.validations?.push({
-          rule: 'require',
-          errorText: warningTrans('required', { name: label }),
-        });
-      }
-
-      if (isInt) {
-        config.validations?.push({
-          rule: 'integer',
-          errorText: warningTrans('integer', { name: label }),
-        });
-      }
-
-      if (typeof min === 'number' && typeof max === 'number') {
-        config.validations?.push({
-          rule: 'range',
-          errorText: warningTrans('range', { name: label, min, max }),
-          extraParam: { min, max, type: 'number' },
-        });
-      }
-
-      // search_k
-      if (isSearchK) {
-        config.validations?.push({
-          rule: 'specValueOrRange',
-          errorText: warningTrans('specValueOrRange', {
-            name: label,
-            min,
-            max,
-            specValue: -1,
-          }),
-          extraParam: {
-            min,
-            max,
-            compareValue: -1,
-            type: 'number',
-          },
-        });
-      }
-      return config;
-    },
-    [warningTrans]
-  );
-
-  const getSearchInputConfig = useCallback(
-    (paramKey: searchKeywordsType): ITextfieldConfig => {
-      const nlist = Number(
-        // nlist range is [1, 65536], if user didn't create index, we set 1024 as default nlist value
-        indexParams.find(p => p.key === 'nlist')?.value || DEFAULT_NLIST_VALUE
-      );
-
-      const configParamMap: {
-        [key in searchKeywordsType]: SearchParamInputConfig;
-      } = {
-        filter: {
-          label: 'filter',
-          key: 'filter',
-          value: searchParamsForm['filter'] ?? '',
-          isInt: false,
-          type: 'text',
-          required: false,
-          handleChange: value => {
-            handleInputChange('filter', value);
-          },
-          className: 'inline-input',
-        },
-        round_decimal: {
-          label: 'round',
-          key: 'round_decimal',
-          type: 'number',
-          value: searchParamsForm['round_decimal'] ?? '',
-          min: -1,
-          max: 10,
-          isInt: true,
-          required: false,
-          handleChange: value => {
-            handleInputChange('round_decimal', value);
-          },
-          className: 'inline-input',
-        },
-        nprobe: {
-          label: 'nprobe',
-          key: 'nprobe',
-          type: 'number',
-          value: searchParamsForm['nprobe'] ?? '',
-          min: 1,
-          max: nlist,
-          isInt: true,
-          handleChange: value => {
-            handleInputChange('nprobe', value);
-          },
-          className: 'inline-input',
-        },
-        radius: {
-          label: 'radius',
-          key: 'radius',
-          type: 'number',
-          value: searchParamsForm['radius'] ?? '',
-          isInt: false,
-          required: false,
-          handleChange: value => {
-            handleInputChange('radius', value);
-          },
-          className: 'inline-input',
-        },
-        range_filter: {
-          label: 'range filter',
-          key: 'range_filter',
-          value: searchParamsForm['range_filter'] ?? '',
-          isInt: false,
-          required: false,
-          type: 'number',
-          handleChange: value => {
-            handleInputChange('range_filter', value);
-          },
-          className: 'inline-input',
-        },
-        ef: {
-          label: 'ef',
-          key: 'ef',
-          value: searchParamsForm['ef'] ?? '',
-          isInt: true,
-          type: 'number',
-          handleChange: value => {
-            handleInputChange('ef', value);
-          },
-        },
-        level: {
-          label: 'level',
-          key: 'level',
-          value: searchParamsForm['level'] ?? 1,
-          min: 1,
-          max: 5,
-          isInt: true,
-          required: false,
-          type: 'number',
-          handleChange: value => {
-            handleInputChange('level', value);
-          },
-        },
-        search_k: {
-          label: 'search_k',
-          key: 'search_k',
-          value: searchParamsForm['search_k'] ?? topK,
-          min: topK,
-          // n * n_trees can be infinity
-          max: Infinity,
-          isInt: true,
-          type: 'number',
-          handleChange: value => {
-            handleInputChange('search_k', value);
-          },
-        },
-        search_length: {
-          label: 'search_length',
-          key: 'search_length',
-          value: searchParamsForm['search_length'] ?? '',
-          min: 10,
-          max: 300,
-          isInt: true,
-          type: 'number',
-          handleChange: value => {
-            handleInputChange('search_length', value);
-          },
-        },
-        search_list: {
-          label: 'search_list',
-          key: 'search_list',
-          value: searchParamsForm['search_list'] ?? '',
-          min: 150,
-          max: 65535,
-          isInt: true,
-          type: 'number',
-          handleChange: value => {
-            handleInputChange('search_list', value);
-          },
-        },
-        drop_ratio_search: {
-          label: 'drop_ratio_search',
-          key: 'drop_ratio_search',
-          value: searchParamsForm['drop_ratio_search'] ?? '',
-          min: 0,
-          max: 1,
-          isInt: false,
-          type: 'number',
-          required: false,
-          handleChange: value => {
-            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];
-      return getInputConfig(param);
-    },
-    [indexParams, searchParamsForm, topK, getInputConfig, handleInputChange]
-  );
-
-  useEffect(() => {
-    // generate different form according to search params
-    const form = searchParams.reduce(
-      (paramsForm, param) => ({
-        ...paramsForm,
-        [param]: DEFAULT_SEARCH_PARAM_VALUE_MAP[param],
-      }),
-      {}
-    );
-    handleFormChange(form);
-  }, []);
-
-  const checkedForm = useMemo(() => {
-    const { ...needCheckItems } = searchParamsForm;
-    return formatForm(needCheckItems);
-  }, [searchParamsForm]);
-
-  const { validation, checkIsValid, disabled } = useFormValidation(checkedForm);
-
-  useEffect(() => {
-    setParamsDisabled(disabled);
-  }, [disabled, setParamsDisabled]);
-
-  return (
-    <Box
-      sx={{
-        ...sx,
-        display: 'flex',
-        flexDirection: 'column',
-        gap: 2,
-        '& .inline-input': {
-          marginBottom: '20px',
-        },
-      }}
-    >
-      {/* dynamic params, now every type only has one param except metric type */}
-      {searchParams.map(param => (
-        <CustomInput
-          key={param}
-          type="text"
-          textConfig={{
-            ...getSearchInputConfig(param),
-            className: 'inline-input',
-            sx: {
-              width: '100%',
-              '& .MuiFormHelperText-root': {
-                position: 'absolute',
-                margin: 0,
-                padding: '0 14px',
-                fontSize: '0.75rem',
-                lineHeight: '1.66',
-                letterSpacing: '0.03333em',
-                textAlign: 'left',
-                marginTop: '3px',
-                marginRight: '14px',
-                marginBottom: '0',
-                marginLeft: '14px',
-              },
-            },
-            variant: 'outlined',
-            InputLabelProps: { shrink: true },
-          }}
-          checkValid={checkIsValid}
-          validInfo={validation}
-        />
-      ))}
-    </Box>
-  );
-};
-
-export default SearchParams;

+ 0 - 67
client/src/pages/search/Types.ts

@@ -1,67 +0,0 @@
-import { searchKeywordsType } from '@/consts';
-import { DataTypeEnum } from '@/consts';
-import type { FieldObject, KeyValuePair } from '@server/types';
-import type { Option } from '@/components/customSelector/Types';
-import type { SxProps, Theme } from '@mui/material/styles';
-
-export interface SearchParamsProps {
-  // default index type is FLAT
-  indexType?: string;
-  // index extra params, e.g. nlist
-  indexParams?: KeyValuePair[];
-  searchParamsForm: {
-    [key in string]: number | string;
-  };
-  handleFormChange: (form: { [key in string]: number | string }) => void;
-  topK: number;
-  handleConsistencyChange: (type: string) => void;
-  setParamsDisabled: (isDisabled: boolean) => void;
-  consistency_level: string;
-  sx: SxProps<Theme>;
-}
-
-export interface SearchResultView {
-  // dynamic field names
-  [key: string]: any;
-  rank: number;
-  distance: number;
-}
-
-export interface FieldOption extends Option {
-  field: FieldObject;
-}
-
-export interface SearchParamInputConfig {
-  label: string;
-  key: searchKeywordsType;
-  min?: number;
-  max?: number;
-  isInt?: boolean;
-  type?: 'number' | 'text';
-  // no value: empty string
-  value: number | string;
-  handleChange: (value: number) => void;
-  className?: string;
-  required?: boolean;
-}
-
-export interface VectorSearchParam {
-  expr?: string;
-  search_params: {
-    anns_field: string; // your vector field name
-    topk: string | number;
-    metric_type: string;
-    params: string;
-  };
-  vectors: any;
-  output_fields: string[];
-  vector_type: DataTypeEnum;
-  travel_timestamp?: string;
-  consistency_level?: string;
-}
-
-export interface SearchResult {
-  // dynamic field names
-  [key: string]: string | number;
-  score: number;
-}

+ 1 - 1
client/src/types/Common.ts

@@ -7,7 +7,7 @@ export interface LabelValuePair {
 
 
 export type FormHelperType = {
 export type FormHelperType = {
   formValue: { [x: string]: any };
   formValue: { [x: string]: any };
-  updateForm: (type: string, value: string) => void;
+  updateForm: (type: string, value: string | number | boolean) => void;
   validation: { [key: string]: IValidationItem };
   validation: { [key: string]: IValidationItem };
   checkIsValid: Function;
   checkIsValid: Function;
   wrapperClass?: string;
   wrapperClass?: string;

+ 1 - 15
client/src/types/SearchTypes.ts

@@ -1,5 +1,5 @@
 import { Option } from '@/components/customSelector/Types';
 import { Option } from '@/components/customSelector/Types';
-import { searchKeywordsType, DataTypeEnum } from '@/consts';
+import { DataTypeEnum } from '@/consts';
 import { FieldObject } from '@server/types';
 import { FieldObject } from '@server/types';
 
 
 export interface SearchParamsProps {
 export interface SearchParamsProps {
@@ -32,20 +32,6 @@ export interface FieldOption extends Option {
   field: FieldObject;
   field: FieldObject;
 }
 }
 
 
-export interface SearchParamInputConfig {
-  label: string;
-  key: searchKeywordsType;
-  min: number;
-  max: number;
-  isInt?: boolean;
-  // no value: empty string
-  value: number | string;
-  handleChange: (value: number) => void;
-  className?: string;
-}
-
-export type VectorSearchParam  = any
-
 export interface SearchResult {
 export interface SearchResult {
   // dynamic field names
   // dynamic field names
   [key: string]: string | number;
   [key: string]: string | number;

+ 3 - 15
client/src/utils/Form.ts

@@ -81,17 +81,7 @@ export const getMetricOptions = (
     case DataTypeStringEnum.BinaryVector:
     case DataTypeStringEnum.BinaryVector:
       switch (indexType) {
       switch (indexType) {
         case 'BIN_FLAT':
         case 'BIN_FLAT':
-          return [
-            ...baseBinaryOptions,
-            {
-              value: METRIC_TYPES_VALUES.SUBSTRUCTURE,
-              label: 'SUBSTRUCTURE',
-            },
-            {
-              value: METRIC_TYPES_VALUES.SUPERSTRUCTURE,
-              label: 'SUPERSTRUCTURE',
-            },
-          ];
+          return baseBinaryOptions;
         case 'BIN_IVF_FLAT':
         case 'BIN_IVF_FLAT':
           return baseBinaryOptions;
           return baseBinaryOptions;
         default:
         default:
@@ -117,15 +107,13 @@ export const getScalarIndexOption = (field: FieldObject): Option[] => {
   // Add options based on fieldType
   // Add options based on fieldType
   if (field.data_type === DataTypeStringEnum.VarChar) {
   if (field.data_type === DataTypeStringEnum.VarChar) {
     options.push(
     options.push(
-      SCALAR_INDEX_OPTIONS.find(
-        opt => opt.value === INDEX_TYPES_ENUM.MARISA_TRIE
-      )!
+      SCALAR_INDEX_OPTIONS.find(opt => opt.value === INDEX_TYPES_ENUM.Trie)!
     );
     );
   }
   }
 
 
   if (isNumericType(field.data_type as DataTypeStringEnum)) {
   if (isNumericType(field.data_type as DataTypeStringEnum)) {
     options.push(
     options.push(
-      SCALAR_INDEX_OPTIONS.find(opt => opt.value === INDEX_TYPES_ENUM.SORT)!
+      SCALAR_INDEX_OPTIONS.find(opt => opt.value === INDEX_TYPES_ENUM.STL_SORT)!
     );
     );
   }
   }
 
 

+ 3 - 3
client/src/utils/Validation.ts

@@ -1,4 +1,4 @@
-import { MetricType, METRIC_TYPES_VALUES } from '@/consts';
+import { METRIC_TYPES_VALUES } from '@/consts';
 import type { CollectionObject } from '@server/types';
 import type { CollectionObject } from '@server/types';
 
 
 export type ValidType =
 export type ValidType =
@@ -38,7 +38,7 @@ export interface IExtraParam {
   type?: 'string' | 'number';
   type?: 'string' | 'number';
 
 
   // used for dimension
   // used for dimension
-  metricType?: MetricType;
+  metricType?: METRIC_TYPES_VALUES;
   multipleNumber?: number;
   multipleNumber?: number;
 
 
   // used for check start item
   // used for check start item
@@ -179,7 +179,7 @@ export const checkMultiple = (param: {
 
 
 export const checkDimension = (param: {
 export const checkDimension = (param: {
   value: string;
   value: string;
-  metricType?: MetricType;
+  metricType?: METRIC_TYPES_VALUES;
   multipleNumber?: number;
   multipleNumber?: number;
 }): boolean => {
 }): boolean => {
   const { value, metricType, multipleNumber } = param;
   const { value, metricType, multipleNumber } = param;