Preview.tsx 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. import { FC, useEffect, useState, useMemo } from 'react';
  2. import { useTranslation } from 'react-i18next';
  3. import AttuGrid from '../../components/grid/Grid';
  4. import { getQueryStyles } from '../query/Styles';
  5. import { CollectionHttp } from '../../http/Collection';
  6. import { FieldHttp } from '../../http/Field';
  7. import { IndexHttp } from '../../http/Index';
  8. import { usePaginationHook } from '../../hooks/Pagination';
  9. import CopyButton from '../../components/advancedSearch/CopyButton';
  10. import { ToolBarConfig } from '../../components/grid/Types';
  11. import CustomToolBar from '../../components/grid/ToolBar';
  12. import { DataTypeStringEnum } from '../collections/Types';
  13. import { generateVector } from '../../utils/Common';
  14. import { DataTypeEnum } from '../../pages/collections/Types';
  15. import {
  16. INDEX_CONFIG,
  17. DEFAULT_SEARCH_PARAM_VALUE_MAP,
  18. } from '../../consts/Milvus';
  19. const Preview: FC<{
  20. collectionName: string;
  21. }> = ({ collectionName }) => {
  22. const [fields, setFields] = useState<any[]>([]);
  23. const [tableLoading, setTableLoading] = useState<any>();
  24. const [queryResult, setQueryResult] = useState<any>();
  25. const [primaryKey, setPrimaryKey] = useState<string>('');
  26. const { t: commonTrans } = useTranslation();
  27. const { t: collectionTrans } = useTranslation('collection');
  28. const copyTrans = commonTrans('copy');
  29. const classes = getQueryStyles();
  30. // Format result list
  31. const queryResultMemo = useMemo(
  32. () =>
  33. queryResult?.map((resultItem: { [key: string]: any }) => {
  34. // Iterate resultItem keys, then format vector(array) items.
  35. const tmp = Object.keys(resultItem).reduce(
  36. (prev: { [key: string]: any }, item: string) => {
  37. if (Array.isArray(resultItem[item])) {
  38. const list2Str = JSON.stringify(resultItem[item]);
  39. prev[item] = (
  40. <div className={classes.vectorTableCell}>
  41. <div>{list2Str}</div>
  42. <CopyButton
  43. label={copyTrans.label}
  44. value={list2Str}
  45. className={classes.copyBtn}
  46. />
  47. </div>
  48. );
  49. } else {
  50. prev[item] = `${resultItem[item]}`;
  51. }
  52. return prev;
  53. },
  54. {}
  55. );
  56. return tmp;
  57. }),
  58. [queryResult, classes.vectorTableCell, classes.copyBtn, copyTrans.label]
  59. );
  60. const {
  61. pageSize,
  62. handlePageSize,
  63. currentPage,
  64. handleCurrentPage,
  65. total,
  66. data: result,
  67. } = usePaginationHook(queryResultMemo || []);
  68. const handlePageChange = (e: any, page: number) => {
  69. handleCurrentPage(page);
  70. };
  71. const loadData = async (collectionName: string) => {
  72. // get schema list
  73. const schemaList = await FieldHttp.getFields(collectionName);
  74. const nameList = schemaList.map(v => ({
  75. name: v.name,
  76. type: v.data_type,
  77. }));
  78. const id = schemaList.find(v => v._isPrimaryKey === true);
  79. const primaryKey = id?._fieldName || '';
  80. const delimiter = id?.data_type === 'Int64' ? '' : '"';
  81. const vectorField = schemaList.find(
  82. v => v.data_type === 'FloatVector' || v.data_type === 'BinaryVector'
  83. );
  84. const anns_field = vectorField?._fieldName!;
  85. const dim = Number(vectorField?._dimension);
  86. const vectors = [generateVector(dim)];
  87. // get search params
  88. const indexesInfo = await IndexHttp.getIndexInfo(collectionName);
  89. const indexType =
  90. indexesInfo.length == 0 ? 'FLAT' : indexesInfo[0]._indexType;
  91. const indexConfig = INDEX_CONFIG[indexType];
  92. const metric_type =
  93. indexesInfo.length === 0 ? 'L2' : indexesInfo[0]._metricType;
  94. const searchParamKey = indexConfig.search[0];
  95. const searchParamValue = DEFAULT_SEARCH_PARAM_VALUE_MAP[searchParamKey];
  96. const searchParam = { [searchParamKey]: searchParamValue };
  97. const params = `${JSON.stringify(searchParam)}`;
  98. setPrimaryKey(primaryKey);
  99. // set fields
  100. setFields(nameList);
  101. // set loading
  102. setTableLoading(true);
  103. try {
  104. // first, search random data to get random id
  105. const searchRes = await CollectionHttp.vectorSearchData(collectionName, {
  106. search_params: {
  107. topk: 100,
  108. anns_field,
  109. metric_type,
  110. params,
  111. },
  112. expr: '',
  113. vectors,
  114. output_fields: [primaryKey],
  115. vector_type: DataTypeEnum[vectorField!._fieldType],
  116. });
  117. // compose random id list expression
  118. const expr = `${primaryKey} in [${searchRes.results
  119. .map((d: any) => `${delimiter}${d.id}${delimiter}`)
  120. .join(',')}]`;
  121. // query by random id
  122. const res = await CollectionHttp.queryData(collectionName, {
  123. expr: expr,
  124. output_fields: nameList.map(i => i.name),
  125. });
  126. const result = res.data;
  127. setQueryResult(result);
  128. } catch (err) {
  129. setQueryResult([]);
  130. } finally {
  131. setTableLoading(false);
  132. }
  133. };
  134. // Get fields at first or collection name changed.
  135. useEffect(() => {
  136. collectionName && loadData(collectionName);
  137. }, [collectionName]);
  138. const toolbarConfigs: ToolBarConfig[] = [
  139. {
  140. type: 'iconBtn',
  141. onClick: () => {
  142. loadData(collectionName);
  143. },
  144. label: collectionTrans('refresh'),
  145. icon: 'refresh',
  146. },
  147. ];
  148. return (
  149. <div className={classes.root}>
  150. <CustomToolBar toolbarConfigs={toolbarConfigs} />
  151. <AttuGrid
  152. toolbarConfigs={[]}
  153. colDefinitions={fields.map(i => ({
  154. id: i.name,
  155. align: 'left',
  156. disablePadding: false,
  157. label: i.name,
  158. }))}
  159. primaryKey={primaryKey}
  160. openCheckBox={false}
  161. isLoading={!!tableLoading}
  162. rows={result}
  163. rowCount={total}
  164. page={currentPage}
  165. onChangePage={handlePageChange}
  166. rowsPerPage={pageSize}
  167. setRowsPerPage={handlePageSize}
  168. />
  169. </div>
  170. );
  171. };
  172. export default Preview;