Preview.tsx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  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 {
  15. FLOAT_INDEX_CONFIG,
  16. BINARY_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 indexConfig =
  90. BINARY_INDEX_CONFIG[indexesInfo[0]._indexType] ||
  91. FLOAT_INDEX_CONFIG[indexesInfo[0]._indexType];
  92. const metric_type = indexesInfo[0]._metricType;
  93. const searchParamKey = indexConfig.search[0];
  94. const searchParamValue = DEFAULT_SEARCH_PARAM_VALUE_MAP[searchParamKey];
  95. const searchParam = { [searchParamKey]: searchParamValue };
  96. const params = `${JSON.stringify(searchParam)}`;
  97. setPrimaryKey(primaryKey);
  98. // Temporarily hide bool field due to incorrect return from SDK.
  99. const fieldWithoutBool = nameList.filter(
  100. i => i.type !== DataTypeStringEnum.Bool
  101. );
  102. // set fields
  103. setFields(fieldWithoutBool);
  104. // set loading
  105. setTableLoading(true);
  106. try {
  107. // first, search random data to get random id
  108. const searchRes = await CollectionHttp.vectorSearchData(collectionName, {
  109. search_params: {
  110. topk: 100,
  111. anns_field,
  112. metric_type,
  113. params,
  114. },
  115. expr: '',
  116. vectors,
  117. output_fields: [primaryKey],
  118. vector_type: Number(vectorField?._fieldId),
  119. });
  120. // compose random id list expression
  121. const expr = `${primaryKey} in [${searchRes.results
  122. .map((d: any) => `${delimiter}${d.id}${delimiter}`)
  123. .join(',')}]`;
  124. // query by random id
  125. const res = await CollectionHttp.queryData(collectionName, {
  126. expr: expr,
  127. output_fields: fieldWithoutBool.map(i => i.name),
  128. });
  129. const result = res.data;
  130. setQueryResult(result);
  131. } catch (err) {
  132. setQueryResult([]);
  133. } finally {
  134. setTableLoading(false);
  135. }
  136. };
  137. // Get fields at first or collection name changed.
  138. useEffect(() => {
  139. collectionName && loadData(collectionName);
  140. }, [collectionName]);
  141. const toolbarConfigs: ToolBarConfig[] = [
  142. {
  143. type: 'iconBtn',
  144. onClick: () => {
  145. loadData(collectionName);
  146. },
  147. label: collectionTrans('refresh'),
  148. icon: 'refresh',
  149. },
  150. ];
  151. return (
  152. <div className={classes.root}>
  153. <CustomToolBar toolbarConfigs={toolbarConfigs} />
  154. <AttuGrid
  155. toolbarConfigs={[]}
  156. colDefinitions={fields.map(i => ({
  157. id: i.name,
  158. align: 'left',
  159. disablePadding: false,
  160. label: i.name,
  161. }))}
  162. primaryKey={primaryKey}
  163. openCheckBox={false}
  164. isLoading={!!tableLoading}
  165. rows={result}
  166. rowCount={total}
  167. page={currentPage}
  168. onChangePage={handlePageChange}
  169. rowsPerPage={pageSize}
  170. setRowsPerPage={handlePageSize}
  171. />
  172. </div>
  173. );
  174. };
  175. export default Preview;