123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- import { Client } from '@elastic/elasticsearch';
- import { Config, Init, Inject, Provide } from '@midwayjs/core';
- import { Context } from '@midwayjs/koa';
- import { floor, get, head } from 'lodash';
- @Provide()
- export class AccurateMatchingService {
- @Config('elasticsearch')
- esConfig: object;
- /**es连接实例 */
- esClient: Client;
- @Inject()
- ctx: Context;
- @Init()
- async initClient() {
- const esClient = new Client(this.esConfig);
- this.esClient = esClient;
- }
- async demand(keyword: string, skip: number = 0, limit: number = 10) {
- const config = { index: 'demand', fields: ['name', 'tags', 'area', 'brief'] };
- return this.search(keyword, config, skip, limit);
- }
- async supply(keyword: string, skip: number = 0, limit: number = 10) {
- const config = { index: 'supply', fields: ['name', 'tags', 'area', 'brief'] };
- return this.search(keyword, config, skip, limit);
- }
- async achievement(keyword: string, skip: number = 0, limit: number = 10) {
- const config = { index: 'achievement', fields: ['name', 'tags', 'area', 'brief'] };
- return this.search(keyword, config, skip, limit);
- }
- async forDemandSearch(keyword: string, skip = 0, limit = 10, id) {
- const fields = ['name', 'tags', 'brief'];
- const config = { index: ['supply', 'achievement'], fields };
- const origin_index = 'demand';
- return await this.manyIndexsSearch(keyword, config, skip, limit, origin_index, id);
- }
- async forSupplySearch(keyword: string, skip = 0, limit = 10, id) {
- const fields = ['name', 'tags', 'brief'];
- const config = { index: ['demand', 'achievement'], fields };
- const origin_index = 'supply';
- return await this.manyIndexsSearch(keyword, config, skip, limit, origin_index, id);
- }
- /**精准匹配统一查询,使用简单的form+size分页模式.如果数据量大于1w,此处的分页模式应该修改,不过就会影响资源的占用及数据的实时性 */
- async search(keyword: string, config: object, skip: number, limit: number) {
- const index = get(config, 'index');
- const fields = get(config, 'fields', []);
- const result = await this.esClient.search({
- index,
- query: {
- bool: {
- must: [
- {
- multi_match: {
- query: keyword,
- fields,
- },
- },
- ],
- },
- },
- size: limit,
- from: skip,
- });
- const returnData = this.dealResponses(result);
- return returnData;
- }
- async manyIndexsSearch(keyword: string, config: object, skip: number, limit: number, origin_index: string, id?: number) {
- const index = get(config, 'index');
- const fields = get(config, 'fields', []);
- const user_id = get(this.ctx, 'user.id');
- const must: any = [
- {
- multi_match: {
- query: keyword,
- fields,
- type: 'best_fields',
- tie_breaker: 0.5,
- },
- },
- ];
- const must_not = [
- {
- match: {
- user: user_id,
- },
- },
- ];
- const filter = [];
- if (id) {
- const res = await this.esClient.search({
- index: origin_index,
- query: { bool: { must: { match: { id } } } },
- });
- const originResult = this.dealResponses(res);
- const industry = get(head(get(originResult, 'data')), 'industry');
- if (industry && industry !== '') {
- filter.push({ term: { industry } });
- }
- }
- const result = await this.esClient.search({
- index,
- query: {
- bool: {
- must,
- must_not,
- filter,
- },
- },
- // highlight: {
- // fields: {
- // name: {
- // pre_tags: ['<em>'],
- // post_tags: ['</em>'],
- // },
- // brief: {
- // pre_tags: ['<em>'],
- // post_tags: ['</em>'],
- // },
- // },
- // },
- size: limit,
- from: skip,
- });
- const returnData = this.dealResponses(result);
- return returnData;
- }
- dealResponses(result) {
- const total = get(result, 'hits.total.value', 0);
- const hits = get(result, 'hits.hits', []);
- const list = [];
- for (const ol of hits) {
- const _score = get(ol, '_score', 0);
- const _source = get(ol, '_index');
- const data = get(ol, '_source', {});
- let recommend = 0;
- /**推荐星数计算:超过5,就都是5颗星.未超过5的都向下取整 */
- if (_score >= 5) recommend = 5;
- else recommend = floor(_score);
- data._recommend = recommend;
- data._source = _source;
- list.push(data);
- }
- return { total, data: list };
- }
- }
|