2
0

Preview.tsx 5.0 KB

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