Ver Fonte

Merge pull request #257 from zilliztech/segments_view

segments view
ryjiang há 1 ano atrás
pai
commit
b4d6e4ed26

+ 14 - 0
client/src/http/Collection.ts

@@ -97,6 +97,20 @@ export class CollectionHttp extends BaseModel implements CollectionView {
     return super.search({ path: this.COLLECTIONS_STATISTICS_URL, params: {} });
     return super.search({ path: this.COLLECTIONS_STATISTICS_URL, params: {} });
   }
   }
 
 
+  static getPSegments(collectionName: string) {
+    return super.search({
+      path: `${this.COLLECTIONS_URL}/${collectionName}/psegments`,
+      params: {},
+    });
+  }
+
+  static getQSegments(collectionName: string) {
+    return super.search({
+      path: `${this.COLLECTIONS_URL}/${collectionName}/qsegments`,
+      params: {},
+    });
+  }
+
   static insertData(collectionName: string, param: InsertDataParam) {
   static insertData(collectionName: string, param: InsertDataParam) {
     return super.create({
     return super.create({
       path: `${this.COLLECTIONS_URL}/${collectionName}/insert`,
       path: `${this.COLLECTIONS_URL}/${collectionName}/insert`,

+ 13 - 0
client/src/i18n/en/collection.ts

@@ -89,6 +89,7 @@ const collectionTrans = {
   schemaTab: 'Schema',
   schemaTab: 'Schema',
   queryTab: 'Data Query',
   queryTab: 'Data Query',
   previewTab: 'Data Preview',
   previewTab: 'Data Preview',
+  segmentsTab: 'Segments',
   startTip: 'Start your data query',
   startTip: 'Start your data query',
   dataQuerylimits:
   dataQuerylimits:
     ' Please note that the maximum number of results for your data query is 16384.',
     ' Please note that the maximum number of results for your data query is 16384.',
@@ -100,6 +101,18 @@ const collectionTrans = {
   // rename dialog
   // rename dialog
   newColNamePlaceholder: 'New Collection Name',
   newColNamePlaceholder: 'New Collection Name',
   newNameInfo: 'Only numbers, letters, and underscores are allowed.',
   newNameInfo: 'Only numbers, letters, and underscores are allowed.',
+
+  // segement
+  segements: 'Segments',
+  segPState: 'Persistent Segment State',
+  partitionID: 'Partition ID',
+  segmentID: 'Segment ID',
+  num_rows: 'Row Count',
+  q_nodeIds: 'Query Node IDs',
+  q_index_name: 'Index Name',
+  q_indexID: 'Index ID',
+  q_state: 'Query Segment State',
+  q_mem_size: 'Memory Size',
 };
 };
 
 
 export default collectionTrans;
 export default collectionTrans;

+ 6 - 0
client/src/pages/collections/Collection.tsx

@@ -12,6 +12,8 @@ import { parseLocationSearch } from '@/utils';
 import Schema from '../schema/Schema';
 import Schema from '../schema/Schema';
 import Query from '../query/Query';
 import Query from '../query/Query';
 import Preview from '../preview/Preview';
 import Preview from '../preview/Preview';
+import Segments from '../segments/Segments';
+
 import { TAB_ENUM } from './Types';
 import { TAB_ENUM } from './Types';
 
 
 const useStyles = makeStyles((theme: Theme) => ({
 const useStyles = makeStyles((theme: Theme) => ({
@@ -77,6 +79,10 @@ const Collection = () => {
       label: collectionTrans('queryTab'),
       label: collectionTrans('queryTab'),
       component: <Query collectionName={collectionName} />,
       component: <Query collectionName={collectionName} />,
     },
     },
+    {
+      label: collectionTrans('segmentsTab'),
+      component: <Segments collectionName={collectionName} />,
+    },
   ];
   ];
 
 
   // exclude parititon on cloud
   // exclude parititon on cloud

+ 143 - 0
client/src/pages/segments/Segments.tsx

@@ -0,0 +1,143 @@
+import { useEffect, useState, FC } from 'react';
+import { useTranslation } from 'react-i18next';
+import { CollectionHttp } from '@/http';
+import { usePaginationHook } from '@/hooks';
+import AttuGrid from '@/components/grid/Grid';
+import { ColDefinitionsType } from '@/components/grid/Types';
+import { ToolBarConfig } from '@/components/grid/Types';
+import CustomToolBar from '@/components/grid/ToolBar';
+import { getQueryStyles } from '../query/Styles';
+import { Segment } from './Types';
+
+const Segments: FC<{
+  collectionName: string;
+}> = ({ collectionName }) => {
+  const classes = getQueryStyles();
+  const [segments, setSegements] = useState<Segment[]>([]);
+  const { t: collectionTrans } = useTranslation('collection');
+  const [loading, setLoading] = useState<boolean>(true);
+
+  const fetchSegments = async () => {
+    setLoading(true);
+
+    const psegments = await CollectionHttp.getPSegments(collectionName);
+    const qsegments = await CollectionHttp.getQSegments(collectionName);
+
+    const combinedArray = psegments.infos.map((p: any) => {
+      const q = qsegments.infos.find((q: any) => q.segmentID === p.segmentID);
+      return {
+        ...p,
+        ...(q &&
+          Object.keys(q).reduce((acc: any, key) => {
+            acc[`q_${key}`] = q[key];
+            return acc;
+          }, {})),
+      };
+    });
+
+    setSegements(combinedArray);
+    setLoading(false);
+  };
+
+  const toolbarConfigs: ToolBarConfig[] = [
+    {
+      type: 'iconBtn',
+      onClick: () => {
+        fetchSegments();
+      },
+      label: collectionTrans('refresh'),
+      icon: 'refresh',
+    },
+  ];
+
+  const colDefinitions: ColDefinitionsType[] = [
+    {
+      id: 'segmentID',
+      align: 'left',
+      disablePadding: false,
+      label: collectionTrans('segmentID'),
+    },
+    {
+      id: 'partitionID',
+      align: 'left',
+      disablePadding: false,
+      label: collectionTrans('partitionID'),
+    },
+    {
+      id: 'state',
+      align: 'left',
+      disablePadding: false,
+      label: collectionTrans('segPState'),
+    },
+    {
+      id: 'num_rows',
+      align: 'left',
+      disablePadding: false,
+      label: collectionTrans('num_rows'),
+    },
+    {
+      id: 'q_nodeIds',
+      align: 'left',
+      disablePadding: false,
+      label: collectionTrans('q_nodeIds'),
+    },
+    {
+      id: 'q_state',
+      align: 'left',
+      disablePadding: false,
+      label: collectionTrans('q_state'),
+    },
+    {
+      id: 'q_index_name',
+      align: 'left',
+      disablePadding: false,
+      label: collectionTrans('q_index_name'),
+    },
+  ];
+
+  useEffect(() => {
+    fetchSegments();
+  }, []);
+
+  const {
+    pageSize,
+    handlePageSize,
+    currentPage,
+    handleCurrentPage,
+    total,
+    data,
+    order,
+    orderBy,
+    handleGridSort,
+  } = usePaginationHook(segments);
+
+  const handlePageChange = (e: any, page: number) => {
+    handleCurrentPage(page);
+  };
+
+  return (
+    <div className={classes.root}>
+      <CustomToolBar toolbarConfigs={toolbarConfigs} />
+
+      <AttuGrid
+        toolbarConfigs={[]}
+        colDefinitions={colDefinitions}
+        rows={data}
+        rowCount={total}
+        primaryKey="name"
+        showPagination={true}
+        openCheckBox={false}
+        page={currentPage}
+        onPageChange={handlePageChange}
+        rowsPerPage={pageSize}
+        setRowsPerPage={handlePageSize}
+        isLoading={loading}
+        order={order}
+        orderBy={orderBy}
+        handleSort={handleGridSort}
+      />
+    </div>
+  );
+};
+
+export default Segments;

+ 17 - 0
client/src/pages/segments/Types.ts

@@ -0,0 +1,17 @@
+export type Segment = {
+  collectionID: string;
+  num_rows: string;
+  partitionID: string;
+  q_collectionID: string;
+  q_indexID: string;
+  q_index_name: string;
+  q_mem_size: string;
+  q_nodeID: string;
+  q_nodeIds: string[];
+  q_num_rows: string;
+  q_partitionID: string;
+  q_segmentID: string;
+  q_state: string;
+  segmentID: string;
+  state: string;
+};

+ 30 - 0
server/src/collections/collections.controller.ts

@@ -51,6 +51,8 @@ export class CollectionController {
     );
     );
     this.router.delete('/:name/alias/:alias', this.dropAlias.bind(this));
     this.router.delete('/:name/alias/:alias', this.dropAlias.bind(this));
     this.router.get('/:name', this.describeCollection.bind(this));
     this.router.get('/:name', this.describeCollection.bind(this));
+
+    // load / release
     this.router.put('/:name/load', this.loadCollection.bind(this));
     this.router.put('/:name/load', this.loadCollection.bind(this));
     this.router.put('/:name/release', this.releaseCollection.bind(this));
     this.router.put('/:name/release', this.releaseCollection.bind(this));
     this.router.post(
     this.router.post(
@@ -81,6 +83,10 @@ export class CollectionController {
       this.createAlias.bind(this)
       this.createAlias.bind(this)
     );
     );
 
 
+    // segements
+    this.router.get('/:name/psegments', this.getPSegement.bind(this));
+    this.router.get('/:name/qsegments', this.getQSegement.bind(this));
+
     return this.router;
     return this.router;
   }
   }
 
 
@@ -327,4 +333,28 @@ export class CollectionController {
       next(error);
       next(error);
     }
     }
   }
   }
+
+  async getPSegement(req: Request, res: Response, next: NextFunction) {
+    const name = req.params?.name;
+    try {
+      const result = await this.collectionsService.getPersistentSegmentInfo({
+        collectionName: name,
+      });
+      res.send(result);
+    } catch (error) {
+      next(error);
+    }
+  }
+
+  async getQSegement(req: Request, res: Response, next: NextFunction) {
+    const name = req.params?.name;
+    try {
+      const result = await this.collectionsService.getQuerySegmentInfo({
+        collectionName: name,
+      });
+      res.send(result);
+    } catch (error) {
+      next(error);
+    }
+  }
 }
 }

+ 21 - 0
server/src/collections/collections.service.ts

@@ -16,6 +16,9 @@ import {
   ShowCollectionsReq,
   ShowCollectionsReq,
   ShowCollectionsType,
   ShowCollectionsType,
   DeleteEntitiesReq,
   DeleteEntitiesReq,
+  GetCompactionStateReq,
+  GetQuerySegmentInfoReq,
+  GePersistentSegmentInfoReq,
 } from '@zilliz/milvus2-sdk-node';
 } from '@zilliz/milvus2-sdk-node';
 import { throwErrorFromSDK } from '../utils/Error';
 import { throwErrorFromSDK } from '../utils/Error';
 import { findKeyValue, genRows } from '../utils/Helper';
 import { findKeyValue, genRows } from '../utils/Helper';
@@ -290,4 +293,22 @@ export class CollectionsService {
 
 
     return await this.insert({ collection_name, fields_data });
     return await this.insert({ collection_name, fields_data });
   }
   }
+
+  async getCompactionState(data: GetCompactionStateReq) {
+    const res = await this.milvusService.client.getCompactionState(data);
+    throwErrorFromSDK(res.status);
+    return res;
+  }
+
+  async getQuerySegmentInfo(data: GetQuerySegmentInfoReq) {
+    const res = await this.milvusService.client.getQuerySegmentInfo(data);
+    throwErrorFromSDK(res.status);
+    return res;
+  }
+
+  async getPersistentSegmentInfo(data: GePersistentSegmentInfoReq) {
+    const res = await this.milvusService.client.getPersistentSegmentInfo(data);
+    throwErrorFromSDK(res.status);
+    return res;
+  }
 }
 }