collections.service.ts 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804
  1. import {
  2. CreateCollectionReq,
  3. DescribeCollectionReq,
  4. DropCollectionReq,
  5. GetCollectionStatisticsReq,
  6. InsertReq,
  7. LoadCollectionReq,
  8. ReleaseLoadCollectionReq,
  9. RenameCollectionReq,
  10. AlterAliasReq,
  11. CreateAliasReq,
  12. ShowCollectionsReq,
  13. ShowCollectionsType,
  14. DeleteEntitiesReq,
  15. GetCompactionStateReq,
  16. GetQuerySegmentInfoReq,
  17. GePersistentSegmentInfoReq,
  18. CompactReq,
  19. HasCollectionReq,
  20. CountReq,
  21. GetLoadStateReq,
  22. CollectionData,
  23. CreateIndexReq,
  24. DescribeIndexReq,
  25. DropIndexReq,
  26. AlterCollectionReq,
  27. DataType,
  28. HybridSearchReq,
  29. SearchSimpleReq,
  30. LoadState,
  31. } from '@zilliz/milvus2-sdk-node';
  32. import { Parser } from '@json2csv/plainjs';
  33. import {
  34. findKeyValue,
  35. getKeyValueListFromJsonString,
  36. genRows,
  37. ROW_COUNT,
  38. convertFieldSchemaToFieldType,
  39. LOADING_STATE,
  40. DYNAMIC_FIELD,
  41. SimpleQueue,
  42. MIN_INT64,
  43. VectorTypes,
  44. cloneObj,
  45. } from '../utils';
  46. import { QueryDto, ImportSampleDto } from './dto';
  47. import {
  48. CollectionObject,
  49. CollectionLazyObject,
  50. FieldObject,
  51. IndexObject,
  52. DescribeCollectionRes,
  53. CountObject,
  54. StatisticsObject,
  55. CollectionFullObject,
  56. DescribeIndexRes,
  57. } from '../types';
  58. import { clientCache } from '../app';
  59. import { clients } from '../socket';
  60. import { WS_EVENTS } from '../utils';
  61. export class CollectionsService {
  62. async showCollections(clientId: string, data?: ShowCollectionsReq) {
  63. const { milvusClient } = clientCache.get(clientId);
  64. const res = await milvusClient.showCollections(data);
  65. return res;
  66. }
  67. async createCollection(clientId: string, data: CreateCollectionReq) {
  68. const { milvusClient } = clientCache.get(clientId);
  69. const res = await milvusClient.createCollection(data);
  70. const newCollection = (await this.getAllCollections(
  71. clientId,
  72. [data.collection_name],
  73. data.db_name
  74. )) as CollectionFullObject[];
  75. return newCollection[0];
  76. }
  77. async describeUnformattedCollection(
  78. clientId: string,
  79. collection_name: string,
  80. db_name?: string
  81. ) {
  82. const { milvusClient } = clientCache.get(clientId);
  83. const res = await milvusClient.describeCollection({
  84. collection_name,
  85. db_name,
  86. });
  87. return res;
  88. }
  89. async describeCollection(clientId: string, data: DescribeCollectionReq) {
  90. const { milvusClient } = clientCache.get(clientId);
  91. const res = (await milvusClient.describeCollection(
  92. data
  93. )) as DescribeCollectionRes;
  94. // get index info for collections
  95. const indexRes = await this.describeIndex(clientId, {
  96. collection_name: data.collection_name,
  97. });
  98. const vectorFields: FieldObject[] = [];
  99. const scalarFields: FieldObject[] = [];
  100. const functionFields: FieldObject[] = [];
  101. // assign function to field
  102. const fieldMap = new Map(
  103. res.schema.fields.map(field => [field.name, field])
  104. );
  105. res.schema.functions.forEach(fn => {
  106. const assignFunction = (fieldName: string) => {
  107. const field = fieldMap.get(fieldName);
  108. if (field) {
  109. field.function = fn;
  110. }
  111. };
  112. fn.output_field_names.forEach(assignFunction);
  113. fn.input_field_names.forEach(assignFunction);
  114. });
  115. // get function input fields
  116. const inputFieldNames = res.schema.functions.reduce((acc, cur) => {
  117. return acc.concat(cur.input_field_names);
  118. }, []);
  119. // append index info to each field
  120. res.schema.fields.forEach((field: FieldObject) => {
  121. // add index
  122. field.index = indexRes.index_descriptions.find(
  123. index => index.field_name === field.name
  124. ) as IndexObject;
  125. // add dimension
  126. field.dimension = Number(field.dim) || -1;
  127. // add max capacity
  128. field.maxCapacity = Number(field.max_capacity) || -1;
  129. // add max length
  130. field.maxLength = Number(field.max_length) || -1;
  131. // classify fields
  132. if (VectorTypes.includes(field.data_type)) {
  133. vectorFields.push(field);
  134. } else {
  135. scalarFields.push(field);
  136. }
  137. if (field.is_primary_key) {
  138. res.schema.primaryField = field;
  139. }
  140. // add functionFields if field name included in inputFieldNames
  141. if (inputFieldNames.includes(field.name)) {
  142. functionFields.push(field);
  143. }
  144. });
  145. // add extra data to schema
  146. res.schema.hasVectorIndex = vectorFields.every(v => v.index);
  147. res.schema.enablePartitionKey = res.schema.fields.some(
  148. v => v.is_partition_key
  149. );
  150. res.schema.scalarFields = scalarFields;
  151. res.schema.vectorFields = vectorFields;
  152. res.schema.functionFields = functionFields;
  153. res.schema.dynamicFields = res.schema.enable_dynamic_field
  154. ? [
  155. {
  156. name: DYNAMIC_FIELD,
  157. data_type: 'JSON',
  158. type_params: [],
  159. index: undefined,
  160. description: '',
  161. index_params: [],
  162. dimension: -1,
  163. maxCapacity: -1,
  164. maxLength: -1,
  165. autoID: false,
  166. fieldID: '',
  167. state: '',
  168. dataType: DataType.JSON,
  169. is_function_output: false,
  170. is_primary_key: false,
  171. },
  172. ]
  173. : [];
  174. return res;
  175. }
  176. async renameCollection(clientId: string, data: RenameCollectionReq) {
  177. const { milvusClient } = clientCache.get(clientId);
  178. const res = await milvusClient.renameCollection(data);
  179. const newCollection = (await this.getAllCollections(
  180. clientId,
  181. [data.new_collection_name],
  182. data.db_name
  183. )) as CollectionFullObject[];
  184. return newCollection[0];
  185. }
  186. async alterCollection(clientId: string, data: AlterCollectionReq) {
  187. const { milvusClient } = clientCache.get(clientId);
  188. const res = await milvusClient.alterCollectionProperties(data);
  189. const newCollection = (await this.getAllCollections(
  190. clientId,
  191. [data.collection_name],
  192. data.db_name
  193. )) as CollectionFullObject[];
  194. return newCollection[0];
  195. }
  196. async dropCollection(clientId: string, data: DropCollectionReq) {
  197. const { milvusClient } = clientCache.get(clientId);
  198. const res = await milvusClient.dropCollection(data);
  199. return res;
  200. }
  201. async loadCollection(clientId: string, data: LoadCollectionReq) {
  202. const { milvusClient } = clientCache.get(clientId);
  203. const res = await milvusClient.loadCollection(data);
  204. return data.collection_name;
  205. }
  206. async loadCollectionAsync(clientId: string, data: LoadCollectionReq) {
  207. const { milvusClient } = clientCache.get(clientId);
  208. const res = await milvusClient.loadCollectionAsync(data);
  209. return data.collection_name;
  210. }
  211. async releaseCollection(clientId: string, data: ReleaseLoadCollectionReq) {
  212. const { milvusClient } = clientCache.get(clientId);
  213. const res = await milvusClient.releaseCollection(data);
  214. // emit update to client
  215. this.updateCollectionsDetails(
  216. clientId,
  217. [data.collection_name],
  218. data.db_name
  219. );
  220. return data.collection_name;
  221. }
  222. async getCollectionStatistics(
  223. clientId: string,
  224. data: GetCollectionStatisticsReq
  225. ) {
  226. const { milvusClient } = clientCache.get(clientId);
  227. const res = await milvusClient.getCollectionStatistics(data);
  228. return res;
  229. }
  230. async getLoadState(clientId: string, data: GetLoadStateReq) {
  231. const { milvusClient } = clientCache.get(clientId);
  232. const res = await milvusClient.getLoadState(data);
  233. return res;
  234. }
  235. async count(clientId: string, data: CountReq) {
  236. const { milvusClient } = clientCache.get(clientId);
  237. let count = 0;
  238. try {
  239. // check if the collection is loaded
  240. const loadStateRes = await milvusClient.getLoadState(data);
  241. if (loadStateRes.state === LoadState.LoadStateLoaded) {
  242. const countRes = await milvusClient.count(data);
  243. count = countRes.data;
  244. } else {
  245. const collectionStatisticsRes = await this.getCollectionStatistics(
  246. clientId,
  247. data
  248. );
  249. count = collectionStatisticsRes.data.row_count;
  250. }
  251. } catch (error) {
  252. console.log('ignore count error');
  253. }
  254. return { rowCount: Number(count) } as CountObject;
  255. }
  256. async insert(clientId: string, data: InsertReq) {
  257. const { milvusClient } = clientCache.get(clientId);
  258. const res = await milvusClient.insert(data);
  259. return res;
  260. }
  261. async upsert(clientId: string, data: InsertReq) {
  262. const { milvusClient } = clientCache.get(clientId);
  263. const res = await milvusClient.upsert(data);
  264. return res;
  265. }
  266. async deleteEntities(clientId: string, data: DeleteEntitiesReq) {
  267. const { milvusClient } = clientCache.get(clientId);
  268. const res = await milvusClient.deleteEntities(data);
  269. return res;
  270. }
  271. async vectorSearch(
  272. clientId: string,
  273. data: HybridSearchReq | SearchSimpleReq
  274. ) {
  275. const { milvusClient } = clientCache.get(clientId);
  276. const now = Date.now();
  277. const searchParams = data as HybridSearchReq;
  278. const isHybrid =
  279. Array.isArray(searchParams.data) && searchParams.data.length > 1;
  280. const singleSearchParams = cloneObj(data) as SearchSimpleReq;
  281. // for 2.3.x milvus
  282. if (searchParams.data && searchParams.data.length === 1) {
  283. delete singleSearchParams.data;
  284. delete singleSearchParams.params;
  285. if (Object.keys(searchParams.data[0].params).length > 0) {
  286. singleSearchParams.params = searchParams.data[0].params;
  287. }
  288. singleSearchParams.data = searchParams.data[0].data;
  289. singleSearchParams.anns_field = searchParams.data[0].anns_field;
  290. singleSearchParams.group_by_field = searchParams.group_by_field;
  291. }
  292. const res = await milvusClient.search(
  293. isHybrid ? searchParams : singleSearchParams
  294. );
  295. const after = Date.now();
  296. Object.assign(res, { latency: after - now });
  297. return res;
  298. }
  299. async createAlias(clientId: string, data: CreateAliasReq) {
  300. const { milvusClient } = clientCache.get(clientId);
  301. const res = await milvusClient.createAlias(data);
  302. const newCollection = (await this.getAllCollections(
  303. clientId,
  304. [data.collection_name],
  305. data.db_name
  306. )) as CollectionFullObject[];
  307. return newCollection[0];
  308. }
  309. async alterAlias(clientId: string, data: AlterAliasReq) {
  310. const { milvusClient } = clientCache.get(clientId);
  311. const res = await milvusClient.alterAlias(data);
  312. return res;
  313. }
  314. async dropAlias(clientId: string, collection_name: string, data: any) {
  315. const { milvusClient } = clientCache.get(clientId);
  316. const res = await milvusClient.dropAlias(data);
  317. const newCollection = (await this.getAllCollections(
  318. clientId,
  319. [collection_name],
  320. data.db_name
  321. )) as CollectionFullObject[];
  322. return newCollection[0];
  323. }
  324. async getReplicas(clientId: string, data: any) {
  325. const { milvusClient } = clientCache.get(clientId);
  326. const res = await milvusClient.getReplicas(data);
  327. return res;
  328. }
  329. async query(
  330. clientId: string,
  331. data: {
  332. collection_name: string;
  333. } & QueryDto
  334. ) {
  335. const { milvusClient } = clientCache.get(clientId);
  336. const now = Date.now();
  337. const res = await milvusClient.query(data);
  338. const after = Date.now();
  339. Object.assign(res, { latency: after - now });
  340. return res;
  341. }
  342. // get single collection details
  343. async getCollection(
  344. clientId: string,
  345. collection: CollectionData,
  346. loadCollection: CollectionData,
  347. lazy: boolean = false,
  348. database?: string
  349. ) {
  350. const { collectionsQueue } = clientCache.get(clientId);
  351. if (lazy) {
  352. // add to lazy queue
  353. collectionsQueue.enqueue(collection.name);
  354. // return lazy object
  355. return {
  356. id: collection.id,
  357. collection_name: collection.name,
  358. createdTime: Number(collection.timestamp),
  359. schema: undefined,
  360. rowCount: undefined,
  361. aliases: undefined,
  362. description: undefined,
  363. autoID: undefined,
  364. loadedPercentage: undefined,
  365. consistency_level: undefined,
  366. replicas: undefined,
  367. loaded: undefined,
  368. } as CollectionLazyObject;
  369. }
  370. // get collection schema and properties
  371. const collectionInfo = await this.describeCollection(clientId, {
  372. collection_name: collection.name,
  373. db_name: database,
  374. });
  375. // get collection statistic data
  376. let count: number;
  377. try {
  378. const res = await this.count(clientId, {
  379. collection_name: collection.name,
  380. db_name: database,
  381. });
  382. count = res.rowCount;
  383. } catch (e) {
  384. console.log('ignore getCollectionStatistics');
  385. }
  386. // extract autoID
  387. const autoID = collectionInfo.schema.fields.find(
  388. v => v.is_primary_key === true
  389. )?.autoID;
  390. // get replica info
  391. let replicas;
  392. try {
  393. replicas = loadCollection
  394. ? await this.getReplicas(clientId, {
  395. collectionID: collectionInfo.collectionID,
  396. db_name: database,
  397. })
  398. : replicas;
  399. } catch (e) {
  400. console.log('ignore getReplica');
  401. }
  402. // loading info
  403. const loadedPercentage = !loadCollection
  404. ? -1
  405. : Number(loadCollection.loadedPercentage);
  406. const status =
  407. loadedPercentage === -1
  408. ? LOADING_STATE.UNLOADED
  409. : loadedPercentage === 100
  410. ? LOADING_STATE.LOADED
  411. : LOADING_STATE.LOADING;
  412. return {
  413. collection_name: collection.name,
  414. schema: collectionInfo.schema,
  415. rowCount: Number(count || 0),
  416. createdTime: parseInt(collectionInfo.created_utc_timestamp, 10),
  417. aliases: collectionInfo.aliases,
  418. description: collectionInfo.schema.description,
  419. autoID,
  420. id: collectionInfo.collectionID,
  421. loadedPercentage,
  422. consistency_level: collectionInfo.consistency_level,
  423. replicas: (replicas && replicas.replicas) || [],
  424. loaded: status === LOADING_STATE.LOADED,
  425. status,
  426. properties: collectionInfo.properties,
  427. };
  428. }
  429. // get all collections details
  430. async getAllCollections(
  431. clientId: string,
  432. collections: string[] = [],
  433. database?: string
  434. ): Promise<CollectionObject[]> {
  435. const currentClient = clientCache.get(clientId);
  436. // clear collectionsQueue if we fetch all collections
  437. if (collections.length === 0) {
  438. currentClient.collectionsQueue.stop();
  439. currentClient.collectionsQueue = new SimpleQueue<string>();
  440. }
  441. // get all collections(name, timestamp, id)
  442. const allCollections = await this.showCollections(clientId, {
  443. db_name: database,
  444. });
  445. // get all loaded collection
  446. const loadedCollections = await this.showCollections(clientId, {
  447. type: ShowCollectionsType.Loaded,
  448. db_name: database,
  449. });
  450. // data container
  451. const data: CollectionObject[] = [];
  452. // get target collections details
  453. const targetCollections = allCollections.data.filter(
  454. d => collections.indexOf(d.name) !== -1
  455. );
  456. const targets =
  457. targetCollections.length > 0 ? targetCollections : allCollections.data;
  458. // sort targets by name
  459. targets.sort((a, b) => a.name.localeCompare(b.name));
  460. // get all collection details
  461. for (let i = 0; i < targets.length; i++) {
  462. const collection = targets[i];
  463. const loadedCollection = loadedCollections.data.find(
  464. v => v.name === collection.name
  465. );
  466. const notLazy = i <= 5; // lazy is true, only load full details for the first 10 collections
  467. data.push(
  468. await this.getCollection(
  469. clientId,
  470. collection,
  471. loadedCollection,
  472. !notLazy,
  473. database
  474. )
  475. );
  476. }
  477. // start the queue
  478. if (currentClient.collectionsQueue.size() > 0) {
  479. currentClient.collectionsQueue.executeNext(
  480. async (collectionsToGet, q) => {
  481. // if the queue is obseleted, return
  482. if (q.isObseleted) {
  483. return;
  484. }
  485. await this.updateCollectionsDetails(
  486. clientId,
  487. collectionsToGet,
  488. database
  489. );
  490. },
  491. 5
  492. );
  493. }
  494. // return data
  495. return data;
  496. }
  497. // update collections details
  498. // send new info to the client
  499. async updateCollectionsDetails(
  500. clientId: string,
  501. collections: string[],
  502. database: string
  503. ) {
  504. try {
  505. // get current socket
  506. const socketClient = clients.get(clientId);
  507. // get collections
  508. const res = await this.getAllCollections(clientId, collections, database);
  509. // emit event to current client
  510. if (socketClient) {
  511. socketClient.emit(WS_EVENTS.COLLECTION_UPDATE, { collections: res });
  512. }
  513. } catch (e) {
  514. console.log('ignore queue error');
  515. }
  516. }
  517. async getLoadedCollections(clientId: string, db_name?: string) {
  518. const data = [];
  519. const res = await this.showCollections(clientId, {
  520. type: ShowCollectionsType.Loaded,
  521. db_name,
  522. });
  523. if (res.data.length > 0) {
  524. for (const item of res.data) {
  525. const { id, name } = item;
  526. const count = this.count(clientId, { collection_name: name, db_name });
  527. data.push({
  528. id,
  529. collection_name: name,
  530. rowCount: count,
  531. ...item,
  532. });
  533. }
  534. }
  535. return data;
  536. }
  537. /**
  538. * Get collections statistics data
  539. * @returns {collectionCount:number, totalData:number}
  540. */
  541. async getStatistics(clientId: string, db_name?: string) {
  542. const data = {
  543. collectionCount: 0,
  544. totalData: 0,
  545. } as StatisticsObject;
  546. const res = await this.showCollections(clientId, { db_name });
  547. data.collectionCount = res.data.length;
  548. if (res.data.length > 0) {
  549. for (const item of res.data) {
  550. const collectionStatistics = await this.getCollectionStatistics(
  551. clientId,
  552. {
  553. collection_name: item.name,
  554. db_name,
  555. }
  556. );
  557. const rowCount = findKeyValue(collectionStatistics.stats, ROW_COUNT);
  558. data.totalData += isNaN(Number(rowCount)) ? 0 : Number(rowCount);
  559. }
  560. }
  561. return data;
  562. }
  563. /**
  564. * Load sample data into collection
  565. */
  566. async importSample(
  567. clientId: string,
  568. { collection_name, size, download, format, db_name }: ImportSampleDto
  569. ) {
  570. const collectionInfo = await this.describeCollection(clientId, {
  571. collection_name,
  572. db_name,
  573. });
  574. const fields_data = genRows(
  575. collectionInfo.schema.fields,
  576. parseInt(size, 10),
  577. collectionInfo.schema.enable_dynamic_field
  578. );
  579. if (download) {
  580. const parser = new Parser({});
  581. const sampleFile =
  582. format === 'csv'
  583. ? parser.parse(fields_data)
  584. : JSON.stringify(fields_data);
  585. // If download is true, return the generated data directly
  586. return { sampleFile };
  587. } else {
  588. // Otherwise, insert the data into the collection
  589. return await this.insert(clientId, {
  590. collection_name,
  591. fields_data,
  592. db_name,
  593. });
  594. }
  595. }
  596. async getCompactionState(clientId: string, data: GetCompactionStateReq) {
  597. const { milvusClient } = clientCache.get(clientId);
  598. const res = await milvusClient.getCompactionState(data);
  599. return res;
  600. }
  601. async getQuerySegmentInfo(clientId: string, data: GetQuerySegmentInfoReq) {
  602. const { milvusClient } = clientCache.get(clientId);
  603. const res = await milvusClient.getQuerySegmentInfo(data);
  604. return res;
  605. }
  606. async getPersistentSegmentInfo(
  607. clientId: string,
  608. data: GePersistentSegmentInfoReq
  609. ) {
  610. const { milvusClient } = clientCache.get(clientId);
  611. const res = await milvusClient.getPersistentSegmentInfo(data);
  612. return res;
  613. }
  614. async compact(clientId: string, data: CompactReq) {
  615. const { milvusClient } = clientCache.get(clientId);
  616. const res = await milvusClient.compact(data);
  617. return res;
  618. }
  619. async hasCollection(clientId: string, data: HasCollectionReq) {
  620. const { milvusClient } = clientCache.get(clientId);
  621. const res = await milvusClient.hasCollection(data);
  622. return res;
  623. }
  624. async duplicateCollection(clientId: string, data: RenameCollectionReq) {
  625. const collection = await this.describeCollection(clientId, {
  626. collection_name: data.collection_name,
  627. db_name: data.db_name,
  628. });
  629. const createCollectionParams: CreateCollectionReq = {
  630. collection_name: data.new_collection_name,
  631. fields: collection.schema.fields.map(convertFieldSchemaToFieldType),
  632. consistency_level: collection.consistency_level as any,
  633. enable_dynamic_field: !!collection.schema.enable_dynamic_field,
  634. };
  635. if (
  636. collection.schema.fields.some(f => f.is_partition_key) &&
  637. collection.num_partitions
  638. ) {
  639. createCollectionParams.num_partitions = Number(collection.num_partitions);
  640. }
  641. return await this.createCollection(clientId, createCollectionParams);
  642. }
  643. async emptyCollection(clientId: string, data: HasCollectionReq) {
  644. const { milvusClient } = clientCache.get(clientId);
  645. const pkField = await milvusClient.getPkFieldName(data);
  646. const pkType = await milvusClient.getPkFieldType(data);
  647. const res = await milvusClient.deleteEntities({
  648. collection_name: data.collection_name,
  649. filter:
  650. pkType === 'Int64' ? `${pkField} >= ${MIN_INT64}` : `${pkField} != ''`,
  651. db_name: data.db_name,
  652. });
  653. return res;
  654. }
  655. async createIndex(clientId: string, data: CreateIndexReq) {
  656. const { milvusClient } = clientCache.get(clientId);
  657. await milvusClient.createIndex(data);
  658. // fetch new collections
  659. const newCollection = (await this.getAllCollections(
  660. clientId,
  661. [data.collection_name],
  662. data.db_name
  663. )) as CollectionFullObject[];
  664. return newCollection[0];
  665. }
  666. async describeIndex(clientId: string, data: DescribeIndexReq) {
  667. const { milvusClient } = clientCache.get(clientId);
  668. // If the index description is not in the cache, call the Milvus SDK's describeIndex function
  669. const res = (await milvusClient.describeIndex(data)) as DescribeIndexRes;
  670. res.index_descriptions.map(index => {
  671. // get indexType
  672. index.indexType = (index.params.find(p => p.key === 'index_type')
  673. ?.value || '') as string;
  674. // get metricType
  675. const metricTypePair =
  676. index.params.filter(v => v.key === 'metric_type') || [];
  677. index.metricType = findKeyValue(metricTypePair, 'metric_type') as string;
  678. // get index parameter pairs
  679. const paramsJSONstring = findKeyValue(index.params, 'params'); // params is a json string
  680. const params =
  681. (paramsJSONstring &&
  682. getKeyValueListFromJsonString(paramsJSONstring as string)) ||
  683. [];
  684. index.indexParameterPairs = [...metricTypePair, ...params];
  685. });
  686. // Return the response from the Milvus SDK's describeIndex function
  687. return res;
  688. }
  689. async dropIndex(clientId: string, data: DropIndexReq) {
  690. const { milvusClient, database } = clientCache.get(clientId);
  691. await milvusClient.dropIndex(data);
  692. // fetch new collections
  693. const newCollection = (await this.getAllCollections(
  694. clientId,
  695. [data.collection_name],
  696. data.db_name
  697. )) as CollectionFullObject[];
  698. return newCollection[0];
  699. }
  700. }