lrf 8 ヶ月 前
コミット
4a63ad4007

+ 22 - 0
src/controller/accurateMatching.controller.ts

@@ -0,0 +1,22 @@
+import { Controller, Get, Inject, Query } from '@midwayjs/core';
+import { AccurateMatchingService } from '../service/accurateMatching.service';
+
+@Controller('/am')
+export class AccurateMatchingController {
+  @Inject()
+  amService: AccurateMatchingService;
+  /**
+   * 针对 需求信息 的精准匹配
+   * @param keyword 关键词
+   * @param skip 分页起始位置
+   * @param limit 分页显示数量
+   */
+  @Get('/demand')
+  async demand(@Query('keyword') keyword: string, @Query('skip') skip: number, @Query('limit') limit: number) {
+    const result = await this.amService.demand(keyword, skip, limit);
+    return result;
+  }
+
+  @Get('/supply')
+  async supply(@Query('keyword') keyword: string, @Query('skip') skip: number, @Query('limit') limit: number) {}
+}

+ 79 - 0
src/service/accurateMatching.service.ts

@@ -0,0 +1,79 @@
+import { Client } from '@elastic/elasticsearch';
+import { Config, Init, Provide } from '@midwayjs/core';
+import { floor, get, head } from 'lodash';
+
+@Provide()
+export class AccurateMatchingService {
+  @Config('elasticsearch')
+  esConfig: object;
+  /**es连接实例 */
+  esClient: Client;
+  @Init()
+  async initClient() {
+    const esClient = new Client(this.esConfig);
+    this.esClient = esClient;
+  }
+
+  async demand(keyword: string, skip: number = 0, limit: number = 10) {
+    const configs = [
+      { index: 'supply', fields: ['name', 'tags', 'area', 'brief'] },
+      { index: 'achievement', fields: ['name', 'tags', 'area', 'brief'] },
+    ];
+    return this.search(keyword, configs, skip, limit);
+  }
+
+  async supply(keyword: string, skip: number = 0, limit: number = 10) {
+    const configs = [
+      { index: 'demand', fields: ['name', 'tags', 'area', 'brief'] },
+      { index: 'achievement', fields: ['name', 'tags', 'area', 'brief'] },
+    ];
+    return this.search(keyword, configs, skip, limit);
+  }
+
+  /**精准匹配统一查询,使用简单的form+size分页模式.如果数据量大于1w,此处的分页模式应该修改,不过就会影响资源的占用及数据的实时性 */
+  async search(keyword: string, configs: Array<object>, skip: number, limit: number) {
+    const searches = [];
+    for (const c of configs) {
+      searches.push({ index: get(c, 'index') });
+      const obj = {
+        query: { bool: { must: [{ multi_match: { query: keyword, fields: get(c, 'fields', []) } }] } },
+        sort: [{ _score: { order: 'desc' } }],
+        size: limit,
+        from: skip,
+      };
+      searches.push(obj);
+    }
+    const result = await this.esClient.msearch({
+      searches,
+    });
+    const returnData = this.dealResponses(result);
+    return returnData;
+  }
+
+  dealResponses(result) {
+    const returnData = [];
+    const responses = get(result, 'responses');
+    for (const res of responses) {
+      const status = get(res, 'status');
+      if (status !== 200) continue;
+      const hits = get(res, 'hits', []);
+      if (!hits) continue;
+      const total = get(hits, 'total.value', 0);
+      const originList = get(hits, 'hits', []);
+      const list = [];
+      for (const ol of originList) {
+        const _score = get(ol, '_score', 0);
+        const data = get(ol, '_source', {});
+        let recommend = 0;
+        /**推荐星数计算:超过5,就都是5颗星.未超过5的都向下取整 */
+        if (_score >= 5) recommend = 5;
+        else recommend = floor(_score);
+        data._recommend = recommend;
+        list.push(data);
+      }
+      const table = get(head(originList), '_index');
+      returnData.push({ data: list, total, table });
+    }
+    return returnData;
+  }
+}