Related Links
현재 문서와 관련된 문서를 그래프 탐색 + 스코어링으로 추천하는 모듈. 위키에서 "다음에 읽을 문서"를 제안하여 탐색을 돕는다.
추천 알고리즘은 세 단계로 구성된다: (1) 현재 문서의 backlink, co-citation, 직접 링크한 주제의 이웃에서 후보를 수집하되 현재 문서가 명시적으로 직접 링크한 문서는 제외하고, (2) backlink 증거와 직접 링크한 주제의 이웃 증거를 먼저 계산하고, 희소한 공통 링크와 텍스트 유사도로 이를 보강한 뒤, (3) 링크 밀도와 목록형 문서 구조를 이용해 인덱스/허브 문서를 낮추고, 원점수 분포에서 약한 후보를 걸러낸 다음 문서 타입별로 그룹핑한다.
그래프 탐색
collectRelatedPages는 현재 문서를 직접 설명하거나 같은 주제를 공유하는 문서를 수집한다.
현재 문서가 명시적으로 직접 링크한 문서와 자기 자신은 결과에서 제외되어야 한다 —
이미 본문에서 안내한 링크를 "관련 문서"로 다시 보여주면 추천 영역의 가치가 낮아진다.
A가 직접 링크한 Topic은 제외하고, Topic을 함께 참조하는 Peer만 수집
import { collectRelatedPages } from './src/lib/graph.ts'
const data = {
A: { pagename: 'A', links: new Set(['Topic']), backlinks: new Set() },
Topic: { pagename: 'Topic', links: new Set(), backlinks: new Set(['A', 'Peer']) },
Peer: { pagename: 'Peer', links: new Set(['Topic']), backlinks: new Set() },
}
const result = collectRelatedPages('A', 2, n => data[n])
console.log(JSON.stringify([...result.keys()].sort()))run:wiki
| expr | expected |
|---|---|
. | ["Peer"] |
check:jq
스코어링
Backlink 보너스
Backlink는 직접 링크의 주변 이웃보다 높은 점수를 받는다. "나를 참조하는 문서"는 같은 주제를 공유하는 간접 후보보다 관련성이 높다는 가정에 기반한다 — 누군가 명시적으로 이 문서를 언급했다면, 역방향 관계가 더 강한 연관을 의미한다.
backlink 증거가 주제 이웃 증거보다 높은 점수를 받는지 확인
import { scoreRelatedPages } from './src/lib/graph.ts'
const rel = new Map([
['Peer', { viaForwardNeighborhood: 1 }],
['Bwd', { isBacklink: true, viaBacklinks: 1 }],
])
const cfg = { backlinkBonus: 1.3, hubPenaltyPower: 3, lengthBonusPower: 2 }
const getMeta = n => ({ pagename: n, title: n, brief: '', toc: [], frontMatter: { aliases: [], type: 'Article' }, links: new Set(), backlinks: new Set() })
const getLink = n => ({
pagename: n, title: n, brief: '',
contentLength: 100, frontMatter: { type: 'Article' },
})
const scored = scoreRelatedPages(rel, cfg, getMeta, getLink)
const peer = scored.find(s => s.link.pagename === 'Peer').score
const bwd = scored.find(s => s.link.pagename === 'Bwd').score
console.log(JSON.stringify({ backlinkHigher: bwd > peer }))run:wiki
| expr | expected |
|---|---|
.backlinkHigher | true |
check:jq
결과 그룹핑
최종 결과는 문서 타입별로 그룹핑되고, 각 그룹 내에서 점수순 정렬된다. 타입별 그룹핑(Person, Article, Book 등)을 통해 사용자가 원하는 종류의 관련 문서를 빠르게 찾을 수 있다.
Person(B, A)과 Article(X)을 타입별 그룹핑, 그룹 내 점수순 정렬
import { formatRelatedPages } from './src/lib/graph.ts'
const pages = [
{ link: { pagename: 'B', title: 'B', frontMatter: { type: 'Person' } }, score: 0.8 },
{ link: { pagename: 'A', title: 'A', frontMatter: { type: 'Person' } }, score: 0.9 },
{ link: { pagename: 'X', title: 'X', frontMatter: { type: 'Article' } }, score: 0.9 },
]
const result = formatRelatedPages(pages, 10)
const keys = [...result.keys()].sort()
const firstPerson = result.get('Person')[0][0].pagename
console.log(JSON.stringify({ types: keys, firstPerson }))run:wiki
| expr | expected |
|---|---|
.types | ["Article","Person"] |
.firstPerson | A |
check:jq