Preview.tsx 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. import { FC, useEffect, useState } from 'react';
  2. import { useTranslation } from 'react-i18next';
  3. import AttuGrid from '@/components/grid/Grid';
  4. import { Collection, MilvusIndex } from '@/http';
  5. import { usePaginationHook, useSearchResult } from '@/hooks';
  6. import { generateVector } from '@/utils';
  7. import {
  8. INDEX_CONFIG,
  9. DEFAULT_SEARCH_PARAM_VALUE_MAP,
  10. DYNAMIC_FIELD,
  11. DataTypeEnum,
  12. DataTypeStringEnum,
  13. } from '@/consts';
  14. import { ToolBarConfig } from '@/components/grid/Types';
  15. import CustomToolBar from '@/components/grid/ToolBar';
  16. import { getQueryStyles } from '../query/Styles';
  17. const Preview: FC<{
  18. collectionName: string;
  19. }> = ({ collectionName }) => {
  20. const [fields, setFields] = useState<any[]>([]);
  21. const [tableLoading, setTableLoading] = useState<any>();
  22. const [queryResult, setQueryResult] = useState<any>();
  23. const [primaryKey, setPrimaryKey] = useState<string>('');
  24. const { t: collectionTrans } = useTranslation('collection');
  25. const { t: searchTrans } = useTranslation('search');
  26. const classes = getQueryStyles();
  27. // Format result list
  28. const queryResultMemo = useSearchResult(queryResult, classes);
  29. const {
  30. pageSize,
  31. handlePageSize,
  32. currentPage,
  33. handleCurrentPage,
  34. total,
  35. data: result,
  36. } = usePaginationHook(queryResultMemo || []);
  37. const handlePageChange = (e: any, page: number) => {
  38. handleCurrentPage(page);
  39. };
  40. const loadData = async (collectionName: string) => {
  41. // get schema list
  42. const collection = await Collection.getCollectionInfo(collectionName);
  43. const schemaList = collection.fields!;
  44. let nameList = schemaList.map(v => ({
  45. name: v.name,
  46. type: v.fieldType,
  47. }));
  48. // if the dynamic field is enabled, we add $meta column in the grid
  49. if (collection.enableDynamicField) {
  50. nameList.push({
  51. name: DYNAMIC_FIELD,
  52. type: DataTypeStringEnum.JSON,
  53. });
  54. }
  55. const id = schemaList.find(v => v.isPrimaryKey === true);
  56. const primaryKey = id?.name || '';
  57. const delimiter = id?.fieldType === 'Int64' ? '' : '"';
  58. const vectorField = schemaList.find(
  59. v => v.fieldType === 'FloatVector' || v.fieldType === 'BinaryVector'
  60. );
  61. const anns_field = vectorField?.name!;
  62. const dim = Number(vectorField?.dimension);
  63. const vectors = [
  64. generateVector(vectorField?.fieldType === 'FloatVector' ? dim : dim / 8),
  65. ];
  66. // get search params
  67. const indexesInfo = await MilvusIndex.getIndexInfo(collectionName);
  68. const vectorIndex = indexesInfo.filter(i => i.field_name === anns_field)[0];
  69. const indexType = indexesInfo.length == 0 ? 'FLAT' : vectorIndex.indexType;
  70. const indexConfig = INDEX_CONFIG[indexType];
  71. const metric_type =
  72. indexesInfo.length === 0 ? 'L2' : vectorIndex.metricType;
  73. const searchParamKey = indexConfig.search[0];
  74. const searchParamValue = DEFAULT_SEARCH_PARAM_VALUE_MAP[searchParamKey];
  75. const searchParam = { [searchParamKey]: searchParamValue };
  76. const params = `${JSON.stringify(searchParam)}`;
  77. setPrimaryKey(primaryKey);
  78. // set fields
  79. setFields(nameList);
  80. // set loading
  81. setTableLoading(true);
  82. try {
  83. // first, search random data to get random id
  84. const searchRes = await Collection.vectorSearchData(collectionName, {
  85. search_params: {
  86. topk: 100,
  87. anns_field,
  88. metric_type,
  89. params,
  90. },
  91. expr: '',
  92. vectors,
  93. output_fields: [primaryKey],
  94. vector_type:
  95. DataTypeEnum[vectorField!.fieldType as keyof typeof DataTypeEnum],
  96. });
  97. // compose random id list expression
  98. const expr = `${primaryKey} in [${searchRes.results
  99. .map((d: any) => `${delimiter}${d.id}${delimiter}`)
  100. .join(',')}]`;
  101. // query by random id
  102. const res = await Collection.queryData(collectionName, {
  103. expr: expr,
  104. output_fields: [...nameList.map(i => i.name)],
  105. });
  106. const result = res.data;
  107. setQueryResult(result);
  108. } catch (err) {
  109. setQueryResult([]);
  110. } finally {
  111. setTableLoading(false);
  112. }
  113. };
  114. // Get fields at first or collection name changed.
  115. useEffect(() => {
  116. collectionName && loadData(collectionName);
  117. }, [collectionName]);
  118. const toolbarConfigs: ToolBarConfig[] = [
  119. {
  120. type: 'iconBtn',
  121. onClick: () => {
  122. loadData(collectionName);
  123. },
  124. label: collectionTrans('refresh'),
  125. icon: 'refresh',
  126. },
  127. ];
  128. return (
  129. <div className={classes.root}>
  130. <CustomToolBar toolbarConfigs={toolbarConfigs} />
  131. <AttuGrid
  132. toolbarConfigs={[]}
  133. colDefinitions={fields.map(i => ({
  134. id: i.name,
  135. align: 'left',
  136. disablePadding: false,
  137. label:
  138. i.name === DYNAMIC_FIELD ? searchTrans('dynamicFields') : i.name,
  139. }))}
  140. primaryKey={primaryKey}
  141. openCheckBox={false}
  142. isLoading={!!tableLoading}
  143. rows={result}
  144. rowCount={total}
  145. page={currentPage}
  146. onPageChange={handlePageChange}
  147. rowsPerPage={pageSize}
  148. setRowsPerPage={handlePageSize}
  149. />
  150. </div>
  151. );
  152. };
  153. export default Preview;