collections.controller.ts 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  1. import { NextFunction, Request, Response, Router } from 'express';
  2. import { dtoValidationMiddleware } from '../middleware/validation';
  3. import { CollectionsService } from './collections.service';
  4. import {
  5. LoadCollectionReq,
  6. IndexType,
  7. MetricType,
  8. } from '@zilliz/milvus2-sdk-node';
  9. import {
  10. CreateAliasDto,
  11. CreateCollectionDto,
  12. InsertDataDto,
  13. ImportSampleDto,
  14. QueryDto,
  15. RenameCollectionDto,
  16. DuplicateCollectionDto,
  17. ManageIndexDto,
  18. } from './dto';
  19. export class CollectionController {
  20. private collectionsService: CollectionsService;
  21. private router: Router;
  22. constructor() {
  23. this.collectionsService = new CollectionsService();
  24. this.router = Router();
  25. }
  26. get collectionsServiceGetter() {
  27. return this.collectionsService;
  28. }
  29. generateRoutes() {
  30. // get all collections
  31. this.router.get('/', this.showCollections.bind(this));
  32. this.router.get('/names', this.getCollectionNames.bind(this));
  33. // get all collections statistics
  34. this.router.get('/statistics', this.getStatistics.bind(this));
  35. // index
  36. this.router.post(
  37. '/index',
  38. dtoValidationMiddleware(ManageIndexDto),
  39. this.manageIndex.bind(this)
  40. );
  41. this.router.get('/index', this.describeIndex.bind(this));
  42. // get collection with index info
  43. this.router.get('/:name', this.describeCollection.bind(this));
  44. this.router.get(
  45. '/:name/unformatted',
  46. this.describeUnformattedCollection.bind(this)
  47. );
  48. // get count
  49. this.router.get('/:name/count', this.count.bind(this));
  50. // create collection
  51. this.router.post(
  52. '/',
  53. dtoValidationMiddleware(CreateCollectionDto),
  54. this.createCollection.bind(this)
  55. );
  56. // drop collection
  57. this.router.delete('/:name', this.dropCollection.bind(this));
  58. // rename collection
  59. this.router.post(
  60. '/:name',
  61. dtoValidationMiddleware(RenameCollectionDto),
  62. this.renameCollection.bind(this)
  63. );
  64. // duplicate collection
  65. this.router.post(
  66. '/:name/duplicate',
  67. dtoValidationMiddleware(DuplicateCollectionDto),
  68. this.duplicateCollection.bind(this)
  69. );
  70. // get collection statistics
  71. this.router.get(
  72. '/:name/statistics',
  73. this.getCollectionStatistics.bind(this)
  74. );
  75. // load / release
  76. this.router.put('/:name/load', this.loadCollection.bind(this));
  77. this.router.put('/:name/release', this.releaseCollection.bind(this));
  78. this.router.put('/:name/empty', this.empty.bind(this));
  79. // alter collection
  80. this.router.put(
  81. '/:name/properties',
  82. this.setCollectionProperties.bind(this)
  83. );
  84. // insert data
  85. this.router.post(
  86. '/:name/insert',
  87. dtoValidationMiddleware(InsertDataDto),
  88. this.insert.bind(this)
  89. );
  90. this.router.post(
  91. '/:name/upsert',
  92. dtoValidationMiddleware(InsertDataDto),
  93. this.upsert.bind(this)
  94. );
  95. // insert sample data
  96. this.router.post(
  97. '/:name/importSample',
  98. dtoValidationMiddleware(ImportSampleDto),
  99. this.importSample.bind(this)
  100. );
  101. // we need use req.body, so we can't use delete here
  102. this.router.put('/:name/entities', this.deleteEntities.bind(this));
  103. this.router.post('/:name/search', this.vectorSearch.bind(this));
  104. // query
  105. this.router.post(
  106. '/:name/query',
  107. dtoValidationMiddleware(QueryDto),
  108. this.query.bind(this)
  109. );
  110. // create alias
  111. this.router.post(
  112. '/:name/alias',
  113. dtoValidationMiddleware(CreateAliasDto),
  114. this.createAlias.bind(this)
  115. );
  116. // drop alias
  117. this.router.delete('/:name/alias/:alias', this.dropAlias.bind(this));
  118. // segments
  119. this.router.get('/:name/psegments', this.getPSegment.bind(this));
  120. this.router.get('/:name/qsegments', this.getQSegment.bind(this));
  121. // compact
  122. this.router.put('/:name/compact', this.compact.bind(this));
  123. return this.router;
  124. }
  125. async showCollections(req: Request, res: Response, next: NextFunction) {
  126. const type = parseInt('' + req.query?.type, 10);
  127. try {
  128. const result =
  129. type === 1
  130. ? await this.collectionsService.getLoadedCollections(
  131. req.clientId,
  132. req.db_name
  133. )
  134. : await this.collectionsService.getAllCollections(
  135. req.clientId,
  136. [],
  137. req.db_name
  138. );
  139. res.send(result);
  140. } catch (error) {
  141. next(error);
  142. }
  143. }
  144. async getCollectionNames(req: Request, res: Response, next: NextFunction) {
  145. try {
  146. const db_name = req.query?.db_name;
  147. const request = {} as any;
  148. if (db_name) {
  149. request.db_name = db_name;
  150. }
  151. const result = await this.collectionsService.showCollections(
  152. req.clientId,
  153. request
  154. );
  155. res.send(
  156. result.data
  157. .sort((a, b) => {
  158. // sort by name
  159. return a.name.localeCompare(b.name);
  160. })
  161. .map((item: any) => item.name)
  162. );
  163. } catch (error) {
  164. next(error);
  165. }
  166. }
  167. async getStatistics(req: Request, res: Response, next: NextFunction) {
  168. try {
  169. const result = await this.collectionsService.getStatistics(
  170. req.clientId,
  171. req.db_name
  172. );
  173. res.send(result);
  174. } catch (error) {
  175. next(error);
  176. }
  177. }
  178. async createCollection(req: Request, res: Response, next: NextFunction) {
  179. const createCollectionData = req.body;
  180. if (createCollectionData.loadAfterCreate) {
  181. // build index_params for all fields
  182. const fields = createCollectionData.fields;
  183. const index_params = fields.map((field: any) => {
  184. const params: any = {
  185. field_name: field.name,
  186. index_type: IndexType.AUTOINDEX,
  187. };
  188. if (field.is_function_output) {
  189. params.metric_type = MetricType.BM25;
  190. }
  191. return params;
  192. });
  193. createCollectionData.index_params = index_params;
  194. }
  195. try {
  196. const result = await this.collectionsService.createCollection(
  197. req.clientId,
  198. createCollectionData
  199. );
  200. // load collection after create
  201. if (createCollectionData.loadAfterCreate) {
  202. await this.collectionsService.loadCollectionAsync(req.clientId, {
  203. collection_name: createCollectionData.collection_name,
  204. db_name: req.db_name,
  205. });
  206. }
  207. res.send(result);
  208. } catch (error) {
  209. next(error);
  210. }
  211. }
  212. async renameCollection(req: Request, res: Response, next: NextFunction) {
  213. const name = req.params?.name;
  214. const data = req.body;
  215. try {
  216. const result = await this.collectionsService.renameCollection(
  217. req.clientId,
  218. {
  219. collection_name: name,
  220. ...data,
  221. }
  222. );
  223. res.send(result);
  224. } catch (error) {
  225. next(error);
  226. }
  227. }
  228. async setCollectionProperties(
  229. req: Request,
  230. res: Response,
  231. next: NextFunction
  232. ) {
  233. const name = req.params?.name;
  234. const data = req.body;
  235. try {
  236. const result = await this.collectionsService.alterCollection(
  237. req.clientId,
  238. {
  239. collection_name: name,
  240. ...data,
  241. }
  242. );
  243. res.send(result);
  244. } catch (error) {
  245. next(error);
  246. }
  247. }
  248. async duplicateCollection(req: Request, res: Response, next: NextFunction) {
  249. const name = req.params?.name;
  250. const data = req.body;
  251. try {
  252. const result = await this.collectionsService.duplicateCollection(
  253. req.clientId,
  254. {
  255. collection_name: name,
  256. ...data,
  257. }
  258. );
  259. res.send(result);
  260. } catch (error) {
  261. next(error);
  262. }
  263. }
  264. async dropCollection(req: Request, res: Response, next: NextFunction) {
  265. const name = req.params?.name;
  266. try {
  267. const result = await this.collectionsService.dropCollection(
  268. req.clientId,
  269. {
  270. collection_name: name,
  271. db_name: req.db_name,
  272. }
  273. );
  274. res.send(result);
  275. } catch (error) {
  276. next(error);
  277. }
  278. }
  279. async describeCollection(req: Request, res: Response, next: NextFunction) {
  280. const name = req.params?.name;
  281. try {
  282. const result = await this.collectionsService.getAllCollections(
  283. req.clientId,
  284. [name],
  285. req.db_name
  286. );
  287. res.send(result[0]);
  288. } catch (error) {
  289. next(error);
  290. }
  291. }
  292. async describeUnformattedCollection(
  293. req: Request,
  294. res: Response,
  295. next: NextFunction
  296. ) {
  297. const name = req.params?.name;
  298. try {
  299. const result =
  300. await this.collectionsService.describeUnformattedCollection(
  301. req.clientId,
  302. name,
  303. req.db_name
  304. );
  305. res.send(result);
  306. } catch (error) {
  307. next(error);
  308. }
  309. }
  310. async getCollectionStatistics(
  311. req: Request,
  312. res: Response,
  313. next: NextFunction
  314. ) {
  315. const name = req.params?.name;
  316. try {
  317. const result = await this.collectionsService.getCollectionStatistics(
  318. req.clientId,
  319. {
  320. collection_name: name,
  321. db_name: req.db_name,
  322. }
  323. );
  324. res.send(result);
  325. } catch (error) {
  326. next(error);
  327. }
  328. }
  329. async loadCollection(req: Request, res: Response, next: NextFunction) {
  330. const collection_name = req.params?.name;
  331. const data = req.body;
  332. const param: LoadCollectionReq = { collection_name, db_name: req.db_name };
  333. if (data.replica_number) {
  334. param.replica_number = Number(data.replica_number);
  335. }
  336. try {
  337. const result = await this.collectionsService.loadCollectionAsync(
  338. req.clientId,
  339. param
  340. );
  341. res.send(result);
  342. } catch (error) {
  343. next(error);
  344. }
  345. }
  346. async releaseCollection(req: Request, res: Response, next: NextFunction) {
  347. const name = req.params?.name;
  348. try {
  349. const result = await this.collectionsService.releaseCollection(
  350. req.clientId,
  351. {
  352. collection_name: name,
  353. db_name: req.db_name,
  354. }
  355. );
  356. res.send(result);
  357. } catch (error) {
  358. next(error);
  359. }
  360. }
  361. async insert(req: Request, res: Response, next: NextFunction) {
  362. const name = req.params?.name;
  363. const data = req.body;
  364. try {
  365. const result = await this.collectionsService.insert(req.clientId, {
  366. collection_name: name,
  367. ...data,
  368. });
  369. res.send(result);
  370. } catch (error) {
  371. next(error);
  372. }
  373. }
  374. async upsert(req: Request, res: Response, next: NextFunction) {
  375. const name = req.params?.name;
  376. const data = req.body;
  377. try {
  378. const result = await this.collectionsService.upsert(req.clientId, {
  379. collection_name: name,
  380. ...data,
  381. });
  382. res.send(result);
  383. } catch (error) {
  384. next(error);
  385. }
  386. }
  387. async importSample(req: Request, res: Response, next: NextFunction) {
  388. const data = req.body;
  389. try {
  390. const result = await this.collectionsService.importSample(req.clientId, {
  391. ...data,
  392. });
  393. res.send(result);
  394. } catch (error) {
  395. next(error);
  396. }
  397. }
  398. async deleteEntities(req: Request, res: Response, next: NextFunction) {
  399. const name = req.params?.name;
  400. const data = req.body;
  401. try {
  402. const result = await this.collectionsService.deleteEntities(
  403. req.clientId,
  404. {
  405. collection_name: name,
  406. ...data,
  407. }
  408. );
  409. res.send(result);
  410. } catch (error) {
  411. next(error);
  412. }
  413. }
  414. async vectorSearch(req: Request, res: Response, next: NextFunction) {
  415. const name = req.params?.name;
  416. const data = req.body;
  417. try {
  418. const result = await this.collectionsService.vectorSearch(req.clientId, {
  419. collection_name: name,
  420. ...data,
  421. });
  422. res.send(result);
  423. } catch (error) {
  424. next(error);
  425. }
  426. }
  427. async query(req: Request, res: Response, next: NextFunction) {
  428. const name = req.params?.name;
  429. const data = req.body;
  430. const resultLimit: any = req.query?.limit;
  431. const resultPage: any = req.query?.page;
  432. try {
  433. const limit = parseInt(resultLimit, 10);
  434. const page = isNaN(resultPage) ? 0 : parseInt(resultPage, 10);
  435. const result = await this.collectionsService.query(req.clientId, {
  436. collection_name: name,
  437. ...data,
  438. });
  439. // const queryResultList = result.data;
  440. const queryResultLength = result.data.length;
  441. res.send({ ...result, limit, page, total: queryResultLength });
  442. } catch (error) {
  443. next(error);
  444. }
  445. }
  446. async createAlias(req: Request, res: Response, next: NextFunction) {
  447. const name = req.params?.name;
  448. const data = req.body;
  449. try {
  450. const result = await this.collectionsService.createAlias(req.clientId, {
  451. collection_name: name,
  452. ...data,
  453. });
  454. res.send(result);
  455. } catch (error) {
  456. next(error);
  457. }
  458. }
  459. async dropAlias(req: Request, res: Response, next: NextFunction) {
  460. const alias = req.params?.alias;
  461. const name = req.params?.name;
  462. try {
  463. const result = await this.collectionsService.dropAlias(
  464. req.clientId,
  465. name,
  466. {
  467. alias,
  468. db_name: req.db_name,
  469. }
  470. );
  471. res.send(result);
  472. } catch (error) {
  473. next(error);
  474. }
  475. }
  476. async getReplicas(req: Request, res: Response, next: NextFunction) {
  477. const collectionID = req.params?.collectionID;
  478. try {
  479. const result = await this.collectionsService.getReplicas(req.clientId, {
  480. collectionID,
  481. });
  482. res.send(result);
  483. } catch (error) {
  484. next(error);
  485. }
  486. }
  487. async getPSegment(req: Request, res: Response, next: NextFunction) {
  488. const name = req.params?.name;
  489. try {
  490. const result = await this.collectionsService.getPersistentSegmentInfo(
  491. req.clientId,
  492. {
  493. collectionName: name,
  494. dbName: req.db_name,
  495. }
  496. );
  497. res.send(result.infos);
  498. } catch (error) {
  499. next(error);
  500. }
  501. }
  502. async getQSegment(req: Request, res: Response, next: NextFunction) {
  503. const name = req.params?.name;
  504. try {
  505. const result = await this.collectionsService.getQuerySegmentInfo(
  506. req.clientId,
  507. {
  508. collectionName: name,
  509. dbName: req.db_name,
  510. }
  511. );
  512. res.send(result.infos);
  513. } catch (error) {
  514. next(error);
  515. }
  516. }
  517. async compact(req: Request, res: Response, next: NextFunction) {
  518. const name = req.params?.name;
  519. try {
  520. const result = await this.collectionsService.compact(req.clientId, {
  521. collection_name: name,
  522. db_name: req.db_name,
  523. });
  524. res.send(result);
  525. } catch (error) {
  526. next(error);
  527. }
  528. }
  529. async count(req: Request, res: Response, next: NextFunction) {
  530. const name = req.params?.name;
  531. try {
  532. const result = await this.collectionsService.count(req.clientId, {
  533. collection_name: name,
  534. db_name: req.db_name,
  535. });
  536. res.send(result);
  537. } catch (error) {
  538. next(error);
  539. }
  540. }
  541. async empty(req: Request, res: Response, next: NextFunction) {
  542. const name = req.params?.name;
  543. try {
  544. const result = await this.collectionsService.emptyCollection(
  545. req.clientId,
  546. {
  547. collection_name: name,
  548. db_name: req.db_name,
  549. }
  550. );
  551. res.send(result);
  552. } catch (error) {
  553. next(error);
  554. }
  555. }
  556. async manageIndex(req: Request, res: Response, next: NextFunction) {
  557. const { type, collection_name, index_name, extra_params, field_name } =
  558. req.body;
  559. try {
  560. const result =
  561. type.toLocaleLowerCase() === 'create'
  562. ? await this.collectionsService.createIndex(req.clientId, {
  563. collection_name,
  564. extra_params,
  565. field_name,
  566. index_name,
  567. db_name: req.db_name,
  568. })
  569. : await this.collectionsService.dropIndex(req.clientId, {
  570. collection_name,
  571. field_name,
  572. index_name,
  573. db_name: req.db_name,
  574. });
  575. res.send(result);
  576. } catch (error) {
  577. next(error);
  578. }
  579. }
  580. async describeIndex(req: Request, res: Response, next: NextFunction) {
  581. const data = '' + req.query?.collection_name;
  582. try {
  583. const result = await this.collectionsService.describeIndex(req.clientId, {
  584. collection_name: data,
  585. db_name: req.db_name,
  586. });
  587. res.send(result);
  588. } catch (error) {
  589. next(error);
  590. }
  591. }
  592. }