From 080784ce1a3489f79ae7f6f3d32d4aeb49934dce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EB=8B=A4=EC=8A=AC?= <95472052+Daseul1@users.noreply.github.com> Date: Fri, 1 Apr 2022 22:44:47 +0900 Subject: [PATCH] =?UTF-8?q?[#110]feat:=20=EC=97=98=EB=9D=BC=EC=8A=A4?= =?UTF-8?q?=ED=8B=B1=20=EC=B5=9C=EC=A2=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 6148 -> 6148 bytes ars/elk/logstash/logstash.conf | 2 +- ars/src/apis/art/art.module.ts | 7 +- ars/src/apis/art/art.resolver.ts | 215 +++++++++++++++++++------ ars/src/apis/art/art.service.ts | 6 +- ars/src/apis/art/dto/createArtInput.ts | 19 ++- ars/src/apis/payment/payment.module.ts | 1 + ars/src/app.module.ts | 1 - ars/src/common/graphql/schema.gql | 7 +- 9 files changed, 190 insertions(+), 68 deletions(-) diff --git a/.DS_Store b/.DS_Store index a01032a1ecb864aed704c52444b957d284bfb876..45d21ae6a8f68cc74d24b87504e5179e86777414 100644 GIT binary patch delta 37 tcmZoMXfc@J&&WJ6U^gT4WFE#FoGHc0IZ65XISiX`F-oy*X6N|J4*=$s3_Ab- delta 32 ocmZoMXfc@J&&V_}VE1GL5thmPj8`{*XB1$Y*dV-_o#QV*0JKmF?EnA( diff --git a/ars/elk/logstash/logstash.conf b/ars/elk/logstash/logstash.conf index 84e6a99..7013835 100644 --- a/ars/elk/logstash/logstash.conf +++ b/ars/elk/logstash/logstash.conf @@ -20,6 +20,6 @@ input { output { elasticsearch { hosts => "elasticsearch:9200" - index => "artipul00" + index => "artipul09" } } \ No newline at end of file diff --git a/ars/src/apis/art/art.module.ts b/ars/src/apis/art/art.module.ts index 0a47171..551b1e8 100644 --- a/ars/src/apis/art/art.module.ts +++ b/ars/src/apis/art/art.module.ts @@ -1,5 +1,8 @@ import { Module } from '@nestjs/common'; -import { ElasticsearchModule } from '@nestjs/elasticsearch'; +import { + ElasticsearchModule, + ElasticsearchService, +} from '@nestjs/elasticsearch'; import { TypeOrmModule } from '@nestjs/typeorm'; import { ArtImage } from '../artImage/entities/artImage.entity'; import { Engage } from '../engage/entities/engage.entity'; @@ -11,6 +14,7 @@ import { User } from '../user/entities/user.entity'; import { ArtResolver } from './art.resolver'; import { ArtService } from './art.service'; import { Art } from './entities/art.entity'; +import { ArtsSearch } from './entities/artsSearch.entity'; import { LikeArt } from './entities/likeArt.entity'; @Module({ @@ -22,6 +26,7 @@ import { LikeArt } from './entities/likeArt.entity'; User, Payment, Engage, + ArtsSearch, ]), ElasticsearchModule.register({ node: 'http://elasticsearch:9200', diff --git a/ars/src/apis/art/art.resolver.ts b/ars/src/apis/art/art.resolver.ts index 24ec8f6..05593c9 100644 --- a/ars/src/apis/art/art.resolver.ts +++ b/ars/src/apis/art/art.resolver.ts @@ -31,61 +31,174 @@ export class ArtResolver { @Query(() => [ArtsSearch]) async fetchArts( - @Args('tag1') tag1: string, - @Args('tag2', { nullable: true }) tag2: string, - @Args('tag3', { nullable: true }) tag3: string, - @Args('tag4', { nullable: true }) tag4: string, + @Args({ name: 'tags', type: () => [String] }) tags: string[], ) { - //redis에 캐시되어 있는지 확인하기 - const redisValue = await this.cacheManager.get( - `tag1: ${tag1}, tag2: ${tag2}, tag3: ${tag3}, tag4: ${tag4}`, - ); - if (redisValue) { - return redisValue; + if (tags.length === 1) { + const redisValue = await this.cacheManager.get(`tags: ${tags}`); + if (redisValue) { + return redisValue; + } + + const result = await this.elasticsearchService.search({ + index: 'artipul09', + query: { + bool: { + must: [{ match: { tag1: tags[0] } }], + }, + }, + }); + + if (!result.hits.hits.length) return null; + + const artTags = result.hits.hits.map((el: any) => { + return { + id: el._source.id, + title: el._source.title, + start_price: el._source.start_price, + instant_bid: el._source.instant_bid, + price: el._source.price, + deadline: el._source.deadline, + thumbnail: el._source.thumbnail, + tag1: el._source.tag1, + nickname: el._source.nickname, + }; + }); + + // 엘라스틱서치에서 조회 결과가 있다면, 레디스에 검색결과 캐싱해놓기 + await this.cacheManager.set(`tags: ${tags}`, artTags, { + ttl: 5, + }); + return artTags; + } + + if (tags.length === 2) { + const redisValue = await this.cacheManager.get(`tags: ${tags}`); + if (redisValue) { + return redisValue; + } + + const result = await this.elasticsearchService.search({ + index: 'artipul09', + query: { + bool: { + must: [{ match: { tag1: tags[0] } }, { match: { tag2: tags[1] } }], + }, + }, + }); + + if (!result.hits.hits.length) return null; + + const artTags = result.hits.hits.map((el: any) => { + return { + id: el._source.id, + title: el._source.title, + start_price: el._source.start_price, + instant_bid: el._source.instant_bid, + price: el._source.price, + deadline: el._source.deadline, + thumbnail: el._source.thumbnail, + tag1: el._source.tag1, + tag2: el._source.tag2, + nickname: el._source.nickname, + }; + }); + + // 엘라스틱서치에서 조회 결과가 있다면, 레디스에 검색결과 캐싱해놓기 + await this.cacheManager.set(`tags: ${tags}`, artTags, { + ttl: 5, + }); + return artTags; } - // 레디스에 캐시가 되어있지 않다면, 엘라스틱서치에서 조회하기(유저가 검색한 검색어로 조회하기) - const result = await this.elasticsearchService.search({ - index: 'artipul00', - query: { - bool: { - should: [ - { match: { tag1: tag1 } }, - { match: { tag2: tag2 } }, - { match: { tag3: tag3 } }, - { match: { tag4: tag4 } }, - ], + if (tags.length === 3) { + const redisValue = await this.cacheManager.get(`tags: ${tags}`); + if (redisValue) { + return redisValue; + } + + const result = await this.elasticsearchService.search({ + index: 'artipul09', + query: { + bool: { + must: [ + { match: { tag1: tags[0] } }, + { match: { tag2: tags[1] } }, + { match: { tag3: tags[2] } }, + ], + }, + }, + }); + + if (!result.hits.hits.length) return null; + + const artTags = result.hits.hits.map((el: any) => { + return { + id: el._source.id, + title: el._source.title, + start_price: el._source.start_price, + instant_bid: el._source.instant_bid, + price: el._source.price, + deadline: el._source.deadline, + thumbnail: el._source.thumbnail, + tag1: el._source.tag1, + tag2: el._source.tag2, + tag3: el._source.tag3, + nickname: el._source.nickname, + }; + }); + + // 엘라스틱서치에서 조회 결과가 있다면, 레디스에 검색결과 캐싱해놓기 + await this.cacheManager.set(`tags: ${tags}`, artTags, { + ttl: 5, + }); + return artTags; + } + + if (tags.length === 4) { + const redisValue = await this.cacheManager.get(`tags: ${tags}`); + if (redisValue) { + return redisValue; + } + + const result = await this.elasticsearchService.search({ + index: 'artipul09', + query: { + bool: { + must: [ + { match: { tag1: tags[0] } }, + { match: { tag2: tags[1] } }, + { match: { tag3: tags[2] } }, + { match: { tag4: tags[3] } }, + ], + }, }, - }, - }); - - if (!result.hits.hits.length) return null; - - const artTags = result.hits.hits.map((el: any) => { - return { - id: el._source.id, - title: el._source.title, - start_price: el._source.start_price, - instant_bid: el._source.instant_bid, - price: el._source.price, - deadline: el._source.deadline, - thumbnail: el._source.thumbnail, - tag1: el._source.tag1, - tag2: el._source.tag2, - tag3: el._source.tag3, - tag4: el._source.tag4, - nickname: el._source.nickname, - }; - }); - - // 엘라스틱서치에서 조회 결과가 있다면, 레디스에 검색결과 캐싱해놓기 - await this.cacheManager.set( - `tag1: ${tag1}, tag2: ${tag2}, tag3: ${tag3}, tag4: ${tag4}`, - artTags, - { ttl: 0 }, - ); - // 최종 결과 브라우저에 리턴해주기 - return artTags; + }); + + if (!result.hits.hits.length) return null; + + const artTags = result.hits.hits.map((el: any) => { + return { + id: el._source.id, + title: el._source.title, + start_price: el._source.start_price, + instant_bid: el._source.instant_bid, + price: el._source.price, + deadline: el._source.deadline, + thumbnail: el._source.thumbnail, + tag1: el._source.tag1, + tag2: el._source.tag2, + tag3: el._source.tag3, + tag4: el._source.tag4, + nickname: el._source.nickname, + }; + }); + + // 엘라스틱서치에서 조회 결과가 있다면, 레디스에 검색결과 캐싱해놓기 + await this.cacheManager.set(`tags: ${tags}`, artTags, { + ttl: 5, + }); + return artTags; + } } @Query(() => Art) diff --git a/ars/src/apis/art/art.service.ts b/ars/src/apis/art/art.service.ts index cc6a06b..994db75 100644 --- a/ars/src/apis/art/art.service.ts +++ b/ars/src/apis/art/art.service.ts @@ -134,7 +134,7 @@ export class ArtService { } // 작품 등록 - async create({ image_urls, ...rest }, currentUser) { + async create({ image_urls, tags, ...rest }, currentUser) { const queryRunner = this.connection.createQueryRunner(); await queryRunner.connect(); await queryRunner.startTransaction(); @@ -143,6 +143,10 @@ export class ArtService { ...rest, user: currentUser, thumbnail: image_urls[0], + tag1: tags[0], + tag2: tags[1], + tag3: tags[2], + tag4: tags[3], }); for (let i = 0; i < image_urls.length; i++) { diff --git a/ars/src/apis/art/dto/createArtInput.ts b/ars/src/apis/art/dto/createArtInput.ts index 9e1e6a9..55ed12b 100644 --- a/ars/src/apis/art/dto/createArtInput.ts +++ b/ars/src/apis/art/dto/createArtInput.ts @@ -26,15 +26,18 @@ export class CreateArtInput { @Field(() => Boolean) is_soldout: boolean; - @Field(() => String) - tag1: string; + @Field(() => [String]) + tags: string[]; + + // @Field(() => String) + // tag1: string; - @Field(() => String, { nullable: true }) - tag2?: string; + // @Field(() => String, { nullable: true }) + // tag2?: string; - @Field(() => String, { nullable: true }) - tag3?: string; + // @Field(() => String, { nullable: true }) + // tag3?: string; - @Field(() => String, { nullable: true }) - tag4?: string; + // @Field(() => String, { nullable: true }) + // tag4?: string; } diff --git a/ars/src/apis/payment/payment.module.ts b/ars/src/apis/payment/payment.module.ts index ff81b81..059160c 100644 --- a/ars/src/apis/payment/payment.module.ts +++ b/ars/src/apis/payment/payment.module.ts @@ -1,4 +1,5 @@ import { Module } from '@nestjs/common'; +import { ElasticsearchService } from '@nestjs/elasticsearch'; import { TypeOrmModule } from '@nestjs/typeorm'; import { ArtService } from '../art/art.service'; import { Art } from '../art/entities/art.entity'; diff --git a/ars/src/app.module.ts b/ars/src/app.module.ts index 21ad61a..3affd5c 100644 --- a/ars/src/app.module.ts +++ b/ars/src/app.module.ts @@ -47,7 +47,6 @@ import { PaymentModule } from './apis/payment/payment.module'; entities: [__dirname + '/apis/**/*.entity.*'], synchronize: true, logging: true, - timezone: 'Asia/seoul', }), CacheModule.register({ store: redisStore, diff --git a/ars/src/common/graphql/schema.gql b/ars/src/common/graphql/schema.gql index f553e6e..a840333 100644 --- a/ars/src/common/graphql/schema.gql +++ b/ars/src/common/graphql/schema.gql @@ -135,7 +135,7 @@ type Comment { } type Query { - fetchArts(tag1: String!, tag2: String, tag3: String, tag4: String): [ArtsSearch!]! + fetchArts(tags: [String!]!): [ArtsSearch!]! fetchArt(artId: String!): Art! fetchArtImages(artId: String!): [ArtImage!]! fetchEngageCount: Float! @@ -205,10 +205,7 @@ input CreateArtInput { deadline: DateTime! image_urls: [String!]! is_soldout: Boolean! - tag1: String! - tag2: String - tag3: String - tag4: String + tags: [String!]! } """The `Upload` scalar type represents a file upload."""