import _ from 'lodash' ; import { ARTICLE_STATE } from 'common/enums' ; import logger from 'common/logger' ; import { connectionFromArray , fromConnectionArgs , loadManyFilterError , } from 'common/utils' ; import { ArticleToRelatedArticlesResolver } from 'definitions' ; const resolver = async ( { articleId , authorId , title } , { input } , { dataSources : { articleService , draftService , tagService } } ) => { const { take , skip } = fromConnectionArgs ( input , { defaultTake : 3 } ) ; const buffer = 7 ; const addRec = ( rec , extra ) => _ . uniqBy ( rec . concat ( extra ) , 'id' ) . filter ( ( _rec ) => _rec . id !== articleId ) ; const entranceId = articleId ; const collection = ( await articleService . findCollections ( { entranceId } ) ) . map ( ( { articleId : aid } ) => aid ) ; const ids = [ ] ; let articles = [ ] ; try { const relatedArticles = await articleService . related ( { id : articleId , size : take + buffer , notIn : collection , } ) ; const relatedArticleIds = relatedArticles . map ( ( { id : aid } ) => aid ) ; logger . info ( `[recommendation] article ${ articleId }, title ${ title }, ES result ${ relatedArticleIds }` ) ; articles = await articleService . dataloader . loadMany ( relatedArticleIds ) . then ( loadManyFilterError ) . then ( ( allArticles ) => allArticles . filter ( ( { state } ) => state === ARTICLE_STATE . active ) ) ; } catch ( err ) { logger . error ( `error in recommendation via ES: ${ JSON . stringify ( err ) }` ) ; } if ( articles . length < take + buffer ) { const tagIds = await articleService . findTagIds ( { id : articleId } ) ; for ( const tagId of tagIds ) { if ( articles . length >= take + buffer ) { break ; } const articleIds = await tagService . findArticleIds ( { id : tagId , take : take - ids . length , skip , } ) ; logger . info ( `[recommendation] article ${ articleId }, title ${ title }, tag result ${ articleIds } ` ) ; const articlesFromTag = await articleService . dataloader . loadMany ( articleIds ) ; articles = addRec ( articles , articlesFromTag ) ; } } if ( articles . length < take + buffer ) { const articlesFromAuthor = await articleService . findByAuthor ( authorId , { state : ARTICLE_STATE . active , } ) ; logger . info ( `[recommendation] article ${ articleId }, title ${ title }, author result ${ articlesFromAuthor . map ( ( { id : aid } ) => aid ) } ` ) ; articles = addRec ( articles , articlesFromAuthor ) ; } const randomPick = 1 ; let pick = articles . slice ( 0 , take - randomPick ) ; pick = pick . concat ( _ . sampleSize ( articles . slice ( take - randomPick ) , randomPick ) ) ; const nodes = await draftService . dataloader . loadMany ( pick . map ( ( item ) => item . draftId ) ) ; return connectionFromArray ( nodes , input ) ; } ; export default resolver ;