0x00

리서치 / 교차 서비스 topics

임베딩 기반 후보 생성

후보 생성(retrieval)은 전체 콘텐츠 가운데 랭킹 모델에 넘길 후보를 먼저 골라 내는 단계다. 임베딩 기반 후보 생성은 "유저와 가까운 아이템을 벡터 공간에서 찾는다"는 한 문장으로 요약된다. 그러나 그 한 문장 뒤에는 서로 아주 다른 세 계열이 있다. 계열마다 벡터를 만드는 방법이 다르고, X는 3계열을 동시에 운영한다.

계열 벡터를 만드는 방법 X의 구현
그래프 분해 팔로우 그래프를 커뮤니티로 나누고 소속 정도를 벡터로 삼는다 SimClusters
그래프 임베딩 이종 그래프의 엣지를 학습 목표로 삼는다 TwHIN
Two-tower 유저탑과 아이템탑을 따로 학습하고 내적으로 채점한다 DeepRetrieval, Phoenix retrieval

Two-tower 계열의 DeepRetrieval은 X 2025에서 팔로우하지 않은 계정의 포스트를 찾는 주력 후보 생성기다. Phoenix retrieval은 2026년 공개 코드(xai-org/x-algorithm)에서 같은 일을 하는 후보 소스다.

Meta를 같이 놓으면 비교 기준이 하나 더 생긴다. X 자료로 확인할 수 있는 것은 "벡터를 어떻게 만드는가"(인코더 계열)다. Meta 자료로 확인할 수 있는 것은 대부분 "그 벡터를 어디에 어떻게 담는가"(인덱스)다. 두 자료는 같은 질문의 서로 다른 절반이어서, 한쪽 문헌만 읽으면 다른 쪽이 전혀 보이지 않는다.

두 회사 자료의 차이는 실제 시스템 차이라기보다 공개 채널의 차이일 가능성이 크다 추정(X vs Meta 절). 다만 Meta가 two-tower와 ANN(근사 최근접 이웃 검색)을 이겨야 할 베이스라인으로 쓴 시기에 X는 two-tower로 옮겨 갔고, 이 반대 방향의 움직임은 자료 형태로 설명되지 않는다 추정(같은 절).

계열 1 — 그래프 분해 (SimClusters)

SimClusters의 벡터는 희소 벡터다. 차원 수가 커뮤니티 수와 같고, 대부분의 값이 0이다. 이 벡터는 학습이 아니라 커뮤니티 탐지로 만든다.

파이프라인은 다섯 단계다 확인 — src/scala/com/twitter/simclusters_v2/.

  1. 팔로우 그래프에서 producer(팔로우를 받는 계정)끼리의 코사인 유사도를 만든다. producer 자격은 minActiveFollowers로 정하고, 상위 topK명을 남긴다 확인 — UpdateKnownFor20M145K2020.scala:65-66.
  2. 이웃 수를 maxNeighbors로 자르고, 양방향 점수 가운데 큰 값(Max(score))을 남겨 그래프를 대칭으로 만든다. squareWeightsEnable이 켜져 있으면 엣지 가중치를 cos² × 10으로 바꾼다. 이 10은 하드코딩이다. 옆에 wtCoeff 파라미터가 따로 있지만 여기서는 쓰이지 않는다 확인 — UpdateKnownForSBFRunner.scala:321-339,409-413, UpdateKnownFor20M145K2020.scala:84.
  3. Metropolis-Hastings 커뮤니티 탐지로 KnownFor(producer → 커뮤니티)를 만든다. 이 단계는 주 1회 실행한다(batchIncrement = Days(7)) 확인 — UpdateKnownFor20M145K2020.scala:46.
  4. 팔로우 행렬에 KnownFor를 곱해 유저별 커뮤니티인 InterestedIn을 만든다(InterestedIn = 팔로우행렬 × KnownFor). 이때 socialProofThreshold = 2, maxClustersPerUser = 50을 쓴다 확인 — InterestedInFromKnownFor.scala:85-86,327-336.
  5. 트윗 임베딩은 좋아요가 눌릴 때마다 그 유저의 InterestedIn 벡터를 더해서 실시간으로 누적한다 확인 — simclusters_v2/README.md:65-67, summingbird/storm/TweetJob.scala:123-207.

상수를 인용하기 전에 — 코드 기본값과 실제 프로덕션 실행이 다르다

KnownFor 잡(UpdateKnownFor20M145K2020)의 코드에 보이는 하이퍼파라미터 값은 CLI 인자가 없을 때 쓰는 폴백이다. 이 잡은 하이퍼파라미터를 전부 args.int("name", default) 꼴로 받기 때문이다. 그리고 같은 파일에는 실제 프로덕션 실행 명령이 주석으로 남아 있는데, 두 값이 서로 어긋난다 확인 — UpdateKnownFor20M145K2020.scala:144,155.

파라미터 코드 기본값 주석의 프로덕션 명령 일치?
minActiveFollowers 400 :65 --minActiveFollowers 400 ✅
topK (producer 수) 20,000,000 :66 --topK 20000000 ✅
maxNeighbors 400 :69 --maxNeighbors 100 ❌ 4배
maxEpochs 3 :83 --maxEpochs 4 ❌
wtCoeff 10.0 :84 --wtCoeff 10.0 ✅ (단 위 2번에서 쓰이지 않는다)

옆 파일의 docstring도 maxEpochs를 4로 적는다: "run the clustering algorithm for x iterations (x = 4 in the prod setting)" 확인 — UpdateKnownForSBFRunner.scala:50. 즉 독립된 두 문서가 4를 가리키는데 코드 기본값만 3이다. 인용해야 할 값은 100과 4다 추정.

중요한 사실이 두 가지 더 있다.

  • "커뮤니티 145,000개"는 코드에 없다. 커뮤니티 수 k는 설정으로 정하는 하이퍼파라미터가 아니라 실행 결과로 나타나는 값이다 확인 — repo-wide grep 145000, ModelVersions.scala:11-13, UpdateKnownForSBFRunner.scala:636,646.
    • 정수 145000은 레포 전체에서 README.md:33의 산문 한 줄에만 나온다("In production … k ~= 145000").
    • 그 밖에는 모델 버전 문자열 "20M_145K_2020"뿐이다.
    • 코드에서 k는 지난주 결과에서 이어받는다(maxClusterIdInPreviousAssignment).
  • 알고리즘 본체가 레포에 없다. 레포는 com.twitter.sbf.core.MHAlgorithm을 import만 하고, com/twitter/sbf/ 소스 트리는 없다. 공개된 것은 설정값뿐이다 확인 — UpdateKnownForSBFRunner.scala:5-9.

시간 감쇠의 속도가 계층마다 다르다 확인.

  • InterestedIn의 fav 신호는 반감기가 100일이다 확인 — InterestedInFromKnownFor.scala:286-301.
  • 트윗 임베딩은 반감기가 8시간이다 확인 — summingbird/common/Configs.scala:38.

유저 취향은 느리게 잊고, 콘텐츠 인기는 빠르게 잊는다. 같은 시스템 안에서 두 반감기를 300배(100일 × 24시간 ÷ 8시간) 다르게 정했다 확인 — InterestedInFromKnownFor.scala:291-292, summingbird/common/Configs.scala:38 (c54bec0).

SANN — 검색은 ANN이 아니라 역인덱스 스캔이다

이름은 "SimClusters ANN"이지만, SANN은 HNSW 같은 그래프 인덱스가 아니다. 커뮤니티에서 트윗으로 가는 역인덱스를 브루트포스로 전부 스캔한다 확인 — simclusters-ann/.../ApproximateCosineSimilarity.scala.

스캔 범위는 두 상수로 정한다.

후보 클러스터 최대 50개 스캔 × 클러스터당 트윗 최대 200개 → 점수 누적 → 상위 N

확인 — maxScanClusters = 50, maxTopTweetsPerCluster = 200, SimClustersANNCandidateSource.scala:325-347

채점 모드는 4가지이고, 런타임에 고른다 확인 — :111-119.

  • LogCosine: score / sourceEmbedding.logNorm / log(1 + norm)을 쓴다.
  • Cosine: score / l2norm / sqrt(...)를 쓴다.
  • NoSourceNorm: 소스 정규화를 생략한다.
  • DotProduct: 정규화를 하지 않는다.

프로덕션 기본값은 PairEmbeddingCosineSimilarity이고, minScore = 0.7과 후보 나이 상한 1.days를 쓴다 확인 — :325-347.

희소 벡터라서 이 방식이 성립한다. 0이 아닌 차원이 50개뿐이면, 역인덱스를 스캔하는 쪽이 그래프 인덱스보다 비용이 적다. 조밀 벡터에는 쓸 수 없는 방식이다 추정.

↑ 목차

계열 2 — 그래프 임베딩 (TwHIN)

TwHIN은 이종 그래프(노드와 엣지의 종류가 여럿인 그래프)의 (lhs, relation, rhs) 트리플을 학습한다. TransE 계열이지만, 거리가 아니라 내적을 쓴다. TransE는 앞 노드 벡터에 관계 벡터를 더한 값이 뒤 노드 벡터와 가까워지도록 학습하는 그래프 임베딩 방식이다. TwHIN은 관계 벡터를 RHS 쪽에 더하고, 그 결과와 LHS의 내적을 점수로 쓴다.

translated = x[:, 1, :] + trans_embs      # RHS에 관계 벡터를 더한다
score      = (x[:, 0, :] * translated).sum(-1)

확인 — the-algorithm-ml/projects/twhin/models/models.py:53-54,90

공개 학습 코드에는 문제가 여럿 있어서, 그대로 재현하면 안 된다 확인.

  • 설정 파일 docstring은 "lhs에 변환을 적용"이라고 쓰지만, 코드는 rhs에 적용한다 확인 — config.py:39-41 vs models.py:54.
  • 관계 임베딩을 self.all_trans_embs.data[batch.rels]로 조회한다. .data를 거치므로 autograd에서 분리된다. 이 경로로는 관계 벡터가 학습되지 않는다 확인 — models.py:36.
  • 음성 샘플에 레이블 1을 붙이고, neg_weight로 가중치를 낮춰서 구분한다 확인 — models.py:150-159.
    • 해당 코드는 labels = cat([batch.labels, ones(num_negatives)])다.
  • 음성 점수는 관계 벡터 없이 계산한다. 양성 샘플만 + trans_embs를 받는다 확인 — models.py:67-68,83-87.
  • global_negatives는 대입만 되고 forward()에서 쓰이지 않는다. 죽은 코드다 확인 — models.py:25.
  • 검증 데이터셋 생성은 주석 처리돼 있고, LR 스케줄러는 꺼져 있다(scheduler = None) 확인 — run.py:49, optimizer.py:63-64.

프로덕션 차원 수는 공개되지 않았다. 공개된 설정은 예제용 하나뿐이고(embedding_dim: 4), 테스트 상수는 EMB_DIM = 128이다 확인 — local.yaml, test_models.py:16-17.

서빙 쪽은 학습 코드와 별개로 잘 드러나 있다 확인.

  • Manhattan(X 내부 KV 저장소) 데이터셋을 6종 쓴다 확인 — TwhinEmbeddingsStore.scala:32-49.
    • twhin_user_positive_embeddings, twhin_user_negative_embeddings, twhin_tweet_embeddings, twhin_video_embeddings, 그리고 rebuild 2종이다.
  • 참여가 16회 미만이면 임베딩을 0으로 만든다 확인 — :32-49,57-65.
    • 기준은 MinEngagementCount = 16이고, 그 이상이면 카운트로 나눠 정규화한다.
  • 홈 랭킹 피처로도 들어간다 확인 — TwhinEmbeddingsAdapter.scala:33-46.
    • user.twhin.tw_hi_n.user_engagement_as_float_tensor 등이 그 예다.

즉 TwHIN은 검색용이면서 동시에 랭킹 피처다. 같은 임베딩을 두 군데서 재사용한다.

↑ 목차

계열 3 — Two-tower (DeepRetrieval)

DeepRetrieval은 X 2025의 주력 OON(out-of-network, 팔로우하지 않은 계정의 포스트) 후보 생성기다. 유저탑은 실시간으로 원격 호출하고, 아이템탑의 출력은 미리 계산해 벡터DB에 넣어 둔다.

유저 임베딩 = Hydra EmbeddingGenerationService gRPC 호출
아이템      = VecDB 컬렉션(사전 계산)
검색        = annClient.search(collection, vector, SearchParams(limit, scoreThreshold), filter)

확인 — DeepRetrievalUserEmbeddingQueryFeatureHydrator.scala:92-98, DeepRetrievalUserTweetANNCandidateSource.scala:77-84

u2i와 i2i는 호출 방식부터 다르다 확인. u2i는 유저 벡터로 아이템을 찾고, i2i는 씨앗 아이템과 비슷한 아이템을 찾는다.

  • u2i: 클라이언트가 유저 벡터를 들고 가서 search(vector)를 호출한다.
  • i2i: 벡터를 보내지 않고 searchById(tweetId)를 호출한다. 씨앗 트윗의 벡터는 서버가 직접 찾는다(DeepRetrievalTweetTweetANNCandidateSource.scala:71-77).

지연 예산이 매우 빠듯하다. 유저 임베딩 생성은 요청당 150ms, 전체 250ms이고, 재시도는 1%만 허용한다 확인 — HydraEmbeddingGenerationServiceClientModule.scala:19-40.

벡터 검색에 페이로드 필터가 함께 적용된다. 필터 필드는 category, isHighQuality, isHighNegEngRatio, tier다. 즉 순수 최근접 검색이 아니라 필터링된 ANN이다 확인 — DeepRetrievalUserTweetANNCandidateSource.scala:103-121.

벡터DB 컬렉션이 최소 12개이고, 여러 모델을 동시에 서빙한다 확인 — TweetMixerGlobalParams.scala:461-1149. 컬렉션 이름의 예는 다음과 같다.

  • tweet-deep-retrieval, tweet-deep-retrieval-exp3, tweet-deep-retrieval-media
  • content-exploration-deep-retrieval, content-exploration-text-emb
  • creator-incentive-retrieval-v1, refreshed-twhin-tweet 등

학습 코드는 공개되지 않았다. tweet-mixer/에는 추론 호출만 있고, 모델 구조와 손실 함수, 음성 샘플링이 없다 확인 — repo-wide.

↑ 목차

인덱스 계층 — 세 종류가 공존한다

X 코드에는 용도가 다른 벡터 인덱스가 여럿 함께 있고, 임베딩 계열마다 쓰는 인덱스가 다르다 확인.

인덱스 용도 파라미터
자체 HNSW (Scala/Java) 레거시 ANN 서비스 레포에 프로덕션 값이 없다. 아래를 참조하라
FAISS SWIG 바인딩 IndexHNSWFlat/PQ/SQ —
Qdrant TwHIN 전용 collectionName = "twhin-prod", topK = 100, timeout 20ms
VecDB (자체 thrift) DeepRetrieval 계열 SearchParams(limit, scoreThreshold)와 payload filter
SANN 역인덱스 SimClusters 위를 참조하라

확인 — TwHINANNCandidateSource.scala:76-78, ann/src/main/java/com/twitter/ann/faiss/swig/

HNSW 숫자는 인용하면 안 된다. grep으로 검색되는 세 값이 모두 프로덕션 설정이 아니다 확인.

  • efConstruction = 200과 maxM = 16은 리콜 벤치마크용 예제 코드의 값이다 확인 — ann/.../experimental/Runner.scala:28-29.
    • 같은 main() 안에 dimen = 300, trainDataSetSize = 2000, testDataSetSize = 30이 함께 있다.
  • ef = 800은 JIT 예열용 무작위 쿼리의 값이지, 서빙 기본값이 아니다 확인 — HnswQueryIndexServer.scala:95.
    • warmup() 안에 있는 queryWithDistance(randomQuery(), 100, HnswParams(ef = 800))의 값이다.
  • 실제 값은 전부 잡 인자이고, args.int("ef_construction") 꼴로 받는다 확인 — IndexBuilderApp.scala:59, IndexBuilderFromBQApp.scala:124, IndexingStrategy.scala:50. 인자를 넘기는 설정 파일은 레포에 없다.

같은 주의할 점을 2026 Rust 쪽에서도 확인했다. 모듈 트리에서 연결이 끊긴 스코어러 파일에 p::AUTHOR_DIVERSITY_DECAY 하드코딩 상수가 남아 있었다. "grep으로 숫자가 검색된다"와 "그 숫자가 실제로 돌고 있다"는 다른 이야기다.

모든 임베딩 검색 결과는 memcache로 감싼다. TTL은 600초이고, 20% 지터를 준다. 계산식은 randomizedTTL(ttl, earlyExpiration = 0.2) = ttl - ttl × 0.2 × rand()이다 확인 — Utils.scala:47-49. 동시 만료로 인한 thundering herd를 막으려는 처리다 추정.

예외가 하나 있다. 트윗-트윗 임베딩 ANN만 TTL이 180초다 확인 — DeepRetrievalTweetTweetEmbeddingANNCandidateSource.scala:52.

캐시 코드에는 주의할 점이 하나 있다. MemcachedCandidateSource에서는 캐시가 "꺼진" 경로도 쓰기는 한다. 건너뛰는 것은 읽기뿐이다 확인 — MemcachedCandidateSource.scala:41-53.


↑ 목차

Meta — 재미있는 부분이 인코더가 아니라 인덱스에 있다

Meta의 retrieval 공개 문헌을 시간순으로 놓으면, two-tower가 등장하는 것은 중간 한 번뿐이고 앞뒤는 전부 인덱스 이야기다. 2020년에는 ANN을 기존 역인덱스의 쿼리 언어 안에 추가했다. 2024~2026년에는 HILL처럼 인덱스를 학습시키거나, SilverTorch처럼 인덱스를 모델 텐서 안으로 옮겼다. 이 계보가 묻는 것은 "무슨 임베딩을 쓰나"보다 "인덱스를 무엇으로 볼 것인가"다.

↑ 목차

계층 0 — EBR 2020: ANN을 별도 서비스로 빼지 않았다

Facebook Search의 EBR(Embedding-based Retrieval)은 ANN을 별도 서비스로 빼지 않았다. 대신 기존 Boolean 역인덱스(Unicorn)에 최근접 이웃 연산자를 하나 추가했다 확인 — Embedding-based Retrieval in Facebook Search, KDD 2020 (arXiv 2020-06). Facebook Search 배포 사례이지만, 이후 Meta 전체 retrieval 문헌의 출발점이라 여기에 둔다.

추가한 연산자는 아래 한 줄이다.

(nn <key> :radius <radius>)

이 연산자를 Boolean 쿼리 언어에 넣었기 때문에 임베딩과 term을 자유롭게 섞는 hybrid retrieval 표현식을 쓸 수 있게 됐다 확인.

"By having the (nn) operator as part of our Boolean query language we can now support hybrid retrieval expressions, with arbitrary combinations of embeddings and terms."

예를 들어 (and (term "sports") (nn user_emb :radius 0.3)) 같은 식으로, term 매칭과 임베딩 검색이 한 쿼리 안에서 합성된다. 별도의 ANN 서비스를 붙였다 떼는 구조가 아니다. 논문은 이렇게 만든 이유도 직접 밝힌다 확인. 별도 시스템을 쓰는 대신 기존 프리미티브로 NN을 구현해서, 실시간 갱신, 효율적인 쿼리 계획과 실행, multi-hop 쿼리 지원 같은 기존 기능을 전부 물려받았다는 것이다.

"By implementing NN support in terms of pre-existing primitives, instead of writing a separate system, we inherited all the features of the existing system, such as realtime updates, efficient query planning and execution, and support for multi-hop queries."

논문은 radius 모드와 top-K 모드 가운데 radius 모드를 골랐다 확인. radius 모드가 시스템 성능과 결과 품질 사이에서 더 나은 trade-off를 줄 수 있다고 썼다. 그 가능한 이유로, radius 모드는 매칭 식의 다른 조건이 NN 탐색을 제약하지만 top-K 모드는 인덱스 전체를 스캔해야 한다는 점을 들었다.

"we found that radius mode can give better trade-off of system performance and result quality. One possible reason is that radius mode enables a constrained NN search (constrained by other parts of the matching expression) but top K mode provides a more relaxed operation which needs to scan the whole index to get top K results."

즉 필터는 ANN 결과에 사후 적용되는 것이 아니라, ANN 탐색 자체를 제약한다. X의 DeepRetrieval도 payload 필터를 거는 "필터링된 ANN"이다(계열 3). 다만 X는 벡터DB에 필터를 넘기는 형태이고, Meta 2020에서는 필터가 곧 쿼리 언어다. 같은 문제의식에 대한 두 단계 다른 답이다 추정.

논문은 양자화 튜닝에서 얻은 결과와 운영 지침도 적었다.

  • 데이터 변환에는 PCA와 OPQ를 모두 실험했고, OPQ가 대체로 더 효과적이었다 확인 같은 논문.

    "We experimented with both PCA and OPQ to transform the data, and observed that OPQ is generally more effective."

  • PQ(product quantization, 벡터를 조각내 압축하는 양자화) 바이트 수는 일정 크기를 넘으면 정확도 개선이 제한적이었다 확인 같은 논문: "we found that the accuracy improvement is limited after x > d/4."
  • coarse quantizer로는 IMI와 IVF를 비교해 보라고 권한다 확인 같은 논문: "It is useful to compare between IMI and IVF algorithms."
  • 운영 지침은 오프라인 recall이 아니라 온라인에서 튜닝하라고 명시한다 확인 같은 논문: "Tune nprobe, num_clusters, and pq_bytes online to understand the real perf impact."

논문은 hard negative mining(모델이 positive와 헷갈리기 쉬운 음성 샘플을 골라 학습에 쓰는 기법)도 구체적으로 다뤘다.

  • online HNM은 배치 안의 다른 positive 문서들로 작은 풀을 만들고, 그중 유사도가 가장 높은 문서를 가장 어려운 음성 샘플로 고른다 확인 같은 논문: "select the documents which received the highest similarity scores as the hardest negatives".
  • offline HNM은 다음 순서로 돈다 확인 같은 논문.
    1. 쿼리별로 top K를 생성한다.
    2. hard negative를 선택한다.
    3. 재학습한다.
    4. 이 과정을 반복한다.
  • 가장 어려운 것을 쓰면 안 된다 확인 같은 논문. 랭크 위치별로 샘플링을 비교한 결과를 논문은 이렇게 적었다.

    "using the hardest examples is not the best strategy. We compared sampling from different rank positions and found sampling between rank 101-500 achieved the best model recall."

이 마지막 인용이 실무적으로 가장 가치가 크다 추정. "hard negative를 쓴다"는 서술만 있는 논문이 대부분인데, 이 논문은 어느 랭크 구간에서 뽑는지가 결과를 좌우한다고 수치로 말한 몇 안 되는 1차 출처다 추정.

↑ 목차

계층 1 — SilverTorch (2025~2026): 인덱스를 모델 안의 텐서로 옮겼다

SilverTorch는 아이템 인덱스, 자격 필터, 채점 층, 유저 타워를 전부 하나의 PyTorch 모델 안의 텐서나 연산자로 만들었다 확인 — SilverTorch 블로그, 2026-05-26 / 논문 HTML, arXiv 2025-11 초판.

"Index as Model: Every retrieval component — the item index, eligibility filter, scoring layer and user tower — becomes a tensor or operator inside a single PyTorch model."

SilverTorch의 부품은 셋이다 확인.

부품 무엇 대체 대상
Bloom Index "a bloom-filter-based GPU indexing structure. It addresses the warp divergence of forward index, ensures contiguous memory access through bitwise operations" CPU 역인덱스 필터
fused Int8 ANN kernel "representing embeddings with 8-bit integers and leveraging GPU's dp4a instruction (computing four multiply-adds in one instruction)", "streams item embeddings directly from the embedding table ... avoiding intermediate tensor construction" Faiss-GPU
OverArch "a SilverTorch model includes additional scoring layers (referred to as the OverArch layer)", "The OverArch implements Mixture of Logits (MoL)" 후단 랭킹 일부

보고된 개선 폭은 다음과 같다.

  • Bloom index는 CPU 역인덱스보다 291–523× 빠르다 확인.
  • fused Int8 ANN kernel은 Faiss-GPU보다 2.2–14.7× 빠르다 확인.
  • 전체 처리량은 초당 요청 수 기준으로 23.7× 개선된다 확인.
  • TCO는 20.9× 개선된다 확인.

정책 필터가 GPU 커널 안으로 들어갔다는 것이 핵심이다 추정. 필터를 두는 곳은 세 경우가 모두 다르다.

  • X는 필터를 벡터DB의 payload 조건으로 넘긴다.
  • Meta 2020은 필터를 쿼리 언어의 Boolean 절로 표현했다.
  • SilverTorch는 필터를 모델 forward 안의 bitwise 연산으로 만들었다.

세 세대 모두에서 "필터를 어디에 두느냐"가 아키텍처를 결정한다.

인덱스 갱신 주기와 스트리밍 in-place 갱신은 여기서 반복하지 않는다. 이 내용은 model-freshness.md에 정리돼 있다.

↑ 목차

계층 2 — MoL과 h-indexer: 내적을 버리되 인덱스로 보완한다

Meta의 KDD 2023 논문은 내적 대신 MoL(Mixture of Logits)을 유사도 함수로 쓰고, 그 때문에 쓸 수 없게 된 ANN 인덱스를 h-indexer로 보완한다 확인 — Revisiting Neural Retrieval on Accelerators, KDD 2023 (Meta).

논문의 문제 제기는 명확하다 확인. 내적 기반 모델은 저랭크 추천을 만들고, 내적으로는 복잡한 사용자-아이템 상호작용을 담지 못한다는 것이다. 논문은 이 상호작용이 여러 측면을 가지며 고랭크일 가능성이 크다고 본다.

"dot product-based models produce low-rank recommendations", "dot products cannot capture complex user-item interactions, which are multifaceted and likely high rank."

  • MoL(Mixture of Logits)은 유사도를 더 기본적인 logit 여러 개의 적응형 혼합으로 표현한다 확인 같은 논문: "parameterize ϕθ(u,x) as an adaptive mixture of more elementary logits".
    • 후속 논문의 수식은 ϕ(q,x) = Σ_{p=1..P} π_p(q,x)·⟨f_p(q), g_p(x)⟩이다. 즉 P쌍의 저랭크 임베딩 내적에 adaptive gating weight를 적용한다 확인 — Retrieval with Learned Similarities, Bailu Ding(Microsoft)·Jiaqi Zhai(Meta), arXiv 2024-07.
  • h-indexer는 MoL 앞단에서 후보를 넓게 뽑는 1단 검색이다 확인. MoL은 내적이 아니라서 ANN 인덱스를 쓸 수 없고, 그래서 검색을 2단으로 나눈다 확인.

    "an accelerator friendly algorithm, h-indexer, is used to find a large number of candidates (k′=10⁵) out of a 100M corpus, and then a complex similarity function (e.g., mixture-of-logits) is used to find the final top k (e.g., 100) candidates."

  • 서빙 지연은 최적화된 CPU MIPS(내적이 가장 큰 아이템을 찾는 검색) 베이스라인과 비슷하다 확인.

    "The median serving GPU latency of our proposed architecture is 30ms, comparable with optimized CPU MIPS baseline (20ms)."

정리하면 "내적을 버렸다"가 아니라 "내적을 1단으로 강등했다"이다 추정. 표현력을 올리는 대가를 인덱스 계층 하나를 더 쌓아서 치른다. SilverTorch의 OverArch가 MoL을 구현한다는 문장과 이어 읽으면, MoL은 2023 논문에서 2026 프로덕션 서빙 스택으로 실제로 넘어간 것으로 보인다 추정. 다만 두 문서는 서로를 명시적으로 연결하지 않는다.

⚠ h-indexer는 MoL 논문(2407.15462)에 없다. 출처는 KDD 2023 쪽이다 관찰 2026-08-09. 검사한 코퍼스는 arXiv 2407.15462의 v3·v4 HTML 전문 2건이고, 그 안에서 h-indexer 문자열은 0회 나온다.

↑ 목차

계층 3 — RankGraph: co-engagement 그래프를 retrieval 인덱스로 쓴다

RankGraph 계열은 사용자들이 함께 참여한 관계(co-engagement)로 이은 그래프를 만들어 retrieval에 쓴다 확인.

  • RankGraph는 여러 프로덕트를 가로지르는 이종 그래프(users, posts, ads 등)를 만든다 확인 — arXiv:2509.02942, 2025-09.
    • 이 그래프는 GPU GNN과 contrastive learning을 거쳐 similarity retrieval과 real-time clustering에 쓰인다.
    • 논문은 RankGraph를 recommendation foundation model의 구성요소로 자리매김한다.
  • RankGraph-2는 U2U2I / U2I2I 두 경로를 쓴다 확인 — arXiv HTML 2606.18379, 2026.
    • U2U2I는 유저→유저→아이템, U2I2I는 유저→아이템→아이템 순서로 그래프를 건너간다.
    • 엣지 3종(U-U, I-I, U-I)을 참여 데이터만으로 만든다.
    • I-I 엣지에는 popularity bias를 보정하고, PPR(Personalized PageRank)을 기준으로 이웃을 미리 계산한다.
    • 오프라인 recall이 최대 3.8× 올랐다.
    • 14일 A/B에서 CTR은 +0.96%, CVR은 +2.75% 올랐다. U2U 서빙 인프라 비용의 변화는 −83%다.

RankGraph 계열은 X의 SimClusters와 목표가 다르다 추정. SimClusters는 팔로우 그래프를 커뮤니티로 분해하고 주 1회 갱신한다. RankGraph-2는 참여 그래프를 3시간마다 전부 다시 만든다(model-freshness.md). 소셜 그래프 기반과 행동 그래프 기반의 차이가 그대로 갱신 주기의 차이로 나타난다. 다만 X도 TwHIN에서 참여 엣지를 쓰므로, "X=소셜 / Meta=행동"으로 단순화하면 틀린다.

↑ 목차

계층 4 — Andromeda + HILL/MoNN: 인덱스를 학습시킨다

Meta의 광고 retrieval 엔진 Andromeda는 광고를 여러 층의 계층 인덱스로 정리하고, 이 인덱스를 retrieval 모델과 함께 학습한다 확인 — Meta Andromeda, 2024-12-02.

"Andromeda organizes ads into a hierarchical index with multiple layers, reducing the number of inference steps by focusing only on most relevant nodes." "The hierarchical index and retrieval models are jointly trained, which aligns the index representations with neural networks; this improves both precision and recall compared to commonly used two-tower neural networks or approximate nearest neighbor search."

두 번째 인용의 마지막 구절이 이 노트에서 가장 중요한 한 줄이다. Meta가 two-tower와 ANN을 자기가 이겨야 할 베이스라인으로 명시했다. 이 저장소가 "two-tower가 표준"이라고 적어 온 틀을 1차 출처가 직접 반박한다.

  • 하드웨어로는 Grace Hopper Superchip과 MTIA를 든다 확인: "NVIDIA Grace Hopper Superchip and Meta Training and Inference Accelerator (MTIA) hardware"
  • 성과로는 retrieval recall과 일부 세그먼트의 광고 품질 개선을 보고했다 확인: "+6% recall improvement to the retrieval system, delivering +8% ads quality improvement on selected segments"

Andromeda 계열 인덱스의 내부 구조는 2026년에 논문으로 공개됐다 확인 — Efficient Retrieval Scaling with Hierarchical Indexing for Large Scale Recommendation, Meta, arXiv 2026-04-14.

  • MoNN(Modular Neural Network)은 효율을 유지하면서 내적 하나를 넘어서는 사용자-아이템 상호작용의 학습을 강화한다 확인 같은 논문.

    "enhances the learning of sophisticated user and item interactions beyond a single dot product while maintaining high efficiency."

    • MoNN은 Meta Ads Platform의 foundation retrieval model이다. 논문은 이렇게 밝힌다: "currently in service for recommending advertisements to daily Facebook and Instagram users."
  • HILL은 foundation retrieval model의 메모리를 계층적으로 조직해, 구조를 따라 빠르게 검색하면서도 정확성을 유지하려는 방법이다 확인 같은 논문.

    "aims to hierarchically organize the memory in the foundation retrieval model, such that the searching and retrieval along the structure can be speed up and maintain the exactness."

  • 트리 구축 자체가 학습이다 확인 같은 논문.
    • 논문은 학습 기반의 트리 구축 방법을 목표로 한다고 쓴다: "we aim to design a learning-based tree construction method".
    • 아이템 임베딩을 query로 쓰는 cross-attention을 둔다.
    • residual quantization에서 착안해 입력 아이템 임베딩 사이에 잔차를 넘기려 한다: "inspired by residual quantization ... we aim to pass residue between input item embedding".
    • foundation retrieval model과 함께 학습한다: "enjoys the co-training with the foundation retrieval model."
  • 논문은 추천 시스템 도메인에서 test-time training 개념을 구체화했다고 쓴다 확인 같은 논문.

    "fine-tuning the model on this set further improves inference performance, and concretize the concept of 'test-time training' within the recommendation system domain."

⚠ Andromeda·HILL·MoNN은 전부 광고 쪽 문헌이다. 유기적 피드 retrieval에 같은 스택이 쓰인다는 1차 진술을 찾지 못했다 추정. 검사한 코퍼스는 아래 출처 목록의 Meta 블로그와 논문, 그리고 Transparency Center 시스템 카드 15종(2026-08-09 열람)이다. 미공개 자료까지 없다는 근거는 아니다. 다만 facebook.md가 인용한 2023년 유기 쪽 블로그의 "a novel hierarchical deep neural retrieval architecture" 한 줄과 방향이 같아서, 계보상 연결로 읽을 여지는 있다 추정.

↑ 목차

계층 5 — Instagram: 서빙 비용이 아키텍처를 정한 사례

Instagram은 서빙 비용 제약이 retrieval 모델 구조를 정한 사례다 확인. 자세한 인용과 맥락은 instagram.md에 있다.

  • two-tower를 고른 이유가 정확도가 아니라 캐시다 확인 — Scaling the Instagram Explore recommendations system, 2023-08-09.

    "user and item embeddings can be cached, making inference for the Two Tower model extremely efficient"

    • 글은 ANN에 대해 이렇게만 쓴다: "e.g., FAISS, HNSW, etc".
    • 아이템탑 출력이 캐시 가능하다는 서빙 제약이 모델 구조를 결정했다. 논문에서는 거의 나오지 않는 종류의 이유이고, 이 저장소가 존재하는 이유에 가장 가까운 문장이다.
    • 그 대가로 아이템탑 재학습 주기가 인덱스 재구축 비용에 묶인다. 자세한 내용은 model-freshness.md에 있다.
  • first-stage ranker의 라벨은 second-stage 랭커가 고른 top-K에 들었는지 여부다 확인. 즉 retrieval과 ESR(early-stage ranking)을 랭커의 증류로 만든다.

    "We train the first stage ranker to predict the output of the second stage with the label: PSelect = { media in top K results ranked by the second stage}"

  • IGQL은 retrieval 전용 DSL이고, IG2Vec은 계정 임베딩이다. 2019년 원문이 HTTP 500으로 접근되지 않아서 이 이름들의 1차 근거는 비어 있다 관찰 2026-08-09.
    • 원문 주소는 ai.meta.com/blog/powered-by-ai-instagrams-explore-recommender-system/이다.
    • 직접 요청해 본 URL은 3건이다: ai.meta.com·ai.facebook.com·Medium 미러.
  • 다만 동작 방식 자체는 2020년 글에 남아 있다 확인. 2020년 글은 이 질의 언어를 이름 없이 부르고, 이 노트가 IGQL이라 부르는 그 쿼리는 다음과 같다.
user.let(seed_id=user_id)
    .liked(max_num_to_retrieve=30)
    .account_nn(embedding_config=default)
    .posted_media(max_media_per_account=10)
    .filter(non_recommendable_model_threshold=0.2)
    .rank(ranking_model=default)
    .diversify_by(seed_id, method=round_robin)

이 쿼리의 account_nn(embedding_config=default)는 IG2Vec 계열 계정 임베딩에 최근접 이웃을 더한 것이다 추정. 근거는 메서드 이름 자체가 account nearest-neighbor라는 점이다.

그리고 이 쿼리는 계층 0의 하이브리드 발상과 같다 추정. 임베딩 검색(account_nn), 정책 필터(filter), 랭킹, 다양성이 하나의 retrieval 표현식 안에 들어 있다. Facebook Search 2020의 (nn ...) 연산자와 Instagram 2020 글의 질의 언어가 독립적으로 같은 형태에 도달했다 추정.

↑ 목차

계층 -1 — Facebook 연결 콘텐츠에는 ANN이 아예 없다

Facebook 연결 콘텐츠는 코퍼스가 이미 유저의 연결로 제한돼 있어 임베딩 검색이 필요 없다 추정 — facebook.md. 퍼널 규모가 서술된 것은 비연결 쪽뿐이다 확인 — ai.meta.com, 2023: "billions → thousands → a few hundred".

이 구조가 두 회사 사이의 문헌량 격차를 만든 근본 원인이다 추정. X는 팔로우 그래프의 연결이 적고 OON 비중이 처음부터 커서, retrieval이 곧 제품이었다. Facebook은 2021년까지 연결 콘텐츠가 주력이라 retrieval 문제 자체가 작았다. 비연결 콘텐츠 비중은 2021 11.7%에서 2025 Q4 41.0%로 바뀌었고(facebook.md), 이 시점은 Meta의 retrieval 문헌이 크게 늘어나기 시작한 시점과 겹친다.

↑ 목차

케이스: Netflix — "retrieval 없음" 극단의 두 번째 표본

TMIS 2015 기준으로 Netflix에도 ANN이 없다. Facebook 연결 콘텐츠가 "그래프가 곧 후보 집합"이라 ANN이 없다면, Netflix는 "카탈로그가 곧 후보 집합"이라 ANN이 없다. PVR(고전 세대의 장르 행에서 타이틀 순서를 정하던 랭커)은 "카탈로그 전체(또는 장르 필터된 부분집합)를 회원별로 정렬"한다 확인 — TMIS 2015. 코퍼스가 수천에서 수만이면 브루트포스로 전부 채점할 수 있어서, "가까운 것을 빨리 찾는" 문제 자체가 없다. Netflix는 ANN이 기법이 아니라 코퍼스가 수억이라는 조건의 산물임을 보여 주는 대조군이다.

Netflix도 임베딩은 쓴다. 다만 용도가 다르다.

  • 임베딩 스토어: Foundation Model(FM)이 회원 임베딩과 타이틀 임베딩을 일 단위 배치로 만들어 임베딩 스토어에 넣고, 다운스트림 모델들이 이를 피처와 후보 소스 양쪽으로 재사용한다 확인 — 통합 블로그 2025.
    • X의 TwHIN이 검색용과 랭킹 피처를 겸하는 것과 같은 dual-use 패턴이다. 임베딩 재사용은 코퍼스 크기와 무관하게 성립한다.
    • 통합 블로그는 이 임베딩을 후보 생성에도 쓸 수 있다고만 쓰고, ANN을 쓰는지는 밝히지 않는다 관찰 2026-10-19 (블로그 본문 1건).
  • 신규 타이틀 임베딩은 ID가 아니라 메타데이터로 초기화한다 확인 — FM 블로그 2025.
    • 신규 타이틀은 메타데이터 기반 가중 결합으로 임베딩을 만들고, entity age 기반 어텐션으로 ID 임베딩과의 혼합 비율을 조절한다 확인.
    • X의 TwHIN이 참여 16회 미만이면 임베딩을 0으로 만드는 것(계열 2)과 정반대다. X는 신호가 없으면 버리고, Netflix는 콘텐츠 정보로 채운다.
    • 편성 카탈로그여서(모든 타이틀에 메타데이터가 풍부하다) 가능한 선택이다 추정.
  • 고전 세대의 sims(타이틀 유사도)는 비개인화 유사도 리스트와 개인화 행 선택을 조합한 방식이다 확인 TMIS 2015. i2i의 가장 단순한 형태가 최근까지 살아 있었다.

Netflix 전체 구조는 netflix.md에 있다.

↑ 목차

X vs Meta — 구조적 대조

두 회사 자료의 대조는 실제 시스템 차이라기보다 공개 채널 차이일 가능성이 크다 추정. X는 코드를 공개했고, Meta는 논문과 블로그를 쓴다. 코드는 상수를 드러내고, 논문은 배율을 드러낸다.

축 X Meta
공개된 것 후보 소스의 이름과 상수 (3세대 0bfc279의 home-mixer 소스 11개, 2025 c54bec0의 maxScanClusters = 50과 TTL 600초) 인덱스의 구조와 배율 (Bloom index 291–523×, Int8 kernel 2.2–14.7×)
후보 생성의 단위 이름 붙은 소스를 병렬로 실행한 뒤 concat한다 계층 인덱스를 한 번 타고 내려간다
필터가 적용되는 곳 벡터DB payload 조건과 파이프라인 필터(3세대 0bfc279 17개, 2026-08-14 커밋부터 21개) 쿼리 언어 Boolean 절(2020) → GPU 커널 bitwise(2026)
인코더 SimClusters / TwHIN / two-tower 3계열 동시 운영 two-tower는 한 지면(IG Explore)의 선택지이고, ads 쪽은 명시적으로 그것을 이기려 한다
재미있는 엔지니어링의 위치 인코더와 상수 인덱스
못 보는 것 학습 코드·손실·음성 샘플링 (DeepRetrieval 미공개) 유기적 피드의 소스별 후보 수 분해 (no primary source found)

"X는 인코더 중심, Meta는 인덱스 중심"으로 결론 내면 안 되고, "각자 공개한 절반이 다르다"까지가 안전하다 추정.

다만 자료 형태로 설명되지 않는 것이 하나 있다 추정. Meta는 two-tower와 ANN을 이겨야 할 베이스라인이라고 직접 썼고, X는 2025~2026에 two-tower(DeepRetrieval, Phoenix retrieval)로 옮겨 갔다. 두 회사가 같은 시점에 서로 반대 방향으로 움직였다.


↑ 목차

이 케이스에서 일반화할 수 있는 것

X 한 서비스만 보아도 임베딩 계열, 벡터 검색, 임베딩 재사용, 공개 코드와 상수, 시간 감쇠에 관한 일반화를 얻을 수 있다.

  • 한 서비스가 임베딩 계열을 하나만 쓰지 않는다. X는 SimClusters의 희소 그래프 분해, TwHIN의 그래프 임베딩, DeepRetrieval의 two-tower를 동시에 운영하고, 계열마다 인덱스 기술도 다르다. "무슨 임베딩 쓰나"는 질문 자체가 단수형이라 틀렸다.

  • 벡터 검색은 순수 최근접이 아니다. 프로덕션에서는 payload 필터(품질·티어·카테고리)가 항상 함께 적용된다. 논문의 recall@k와 프로덕션 동작이 다른 첫 번째 이유다.

  • 임베딩은 검색용과 랭킹 피처용으로 재사용된다. TwHIN이 대표적이다. 만드는 비용을 두 곳에서 나눠 갚는다.

  • 희소 벡터면 역인덱스 스캔이 그래프 인덱스보다 낫다. SimClusters가 HNSW를 쓰지 않는 이유다.

  • 공개된 학습 코드는 프로덕션 코드가 아니다. X의 TwHIN 공개 코드를 "X가 이렇게 학습한다"로 읽으면 안 된다. 이 코드는 다음 상태다.

    • 검증 로더가 주석 처리돼 있다.
    • 스케줄러가 꺼져 있다.
    • 관계 임베딩이 .data로 분리돼 있다.
  • 상수는 세 종류이고, 셋 다 프로덕션이 아닐 수 있다.

    1. args.int(name, default)의 default는 폴백이지 실행값이 아니다.
    2. 벤치마크와 warmup 코드의 리터럴은 실행값과 아예 무관하다.
    3. 모듈 트리에서 끊긴 파일의 상수는 실행되지 않는다.

    X의 SimClusters는 같은 파일 주석에 실제 실행 명령이 남아 있어서 첫 번째 경우를 확인할 수 있었다. 그런 단서가 없으면 grep으로 나온 숫자는 인용하면 안 된다.

  • 시간 감쇠 상수가 계층마다 다르다. X는 취향의 반감기가 100일, 콘텐츠의 반감기가 8시간이다. 하나의 반감기로 통일하지 않는다.

Meta 쪽을 함께 놓으면 여기에 다섯 개가 더 더해진다.

  • "벡터 검색을 어디에 둘 것인가"가 아키텍처 결정의 본체다.
    • Meta는 ANN을 별도 서비스로 빼는 대신, 기존 Boolean 역인덱스 안의 연산자((nn <key> :radius <radius>))로 넣었다 확인(EBR, arXiv 2006.11632, KDD 2020).
    • 5년 뒤 SilverTorch에서는 인덱스 자체를 모델 텐서로 만들어 GPU에 올렸다 확인(SilverTorch, arXiv 2511.14881, 2025-11).
    • 두 결정 모두 인코더를 바꾼 것이 아니라 인덱스의 위치를 바꾼 것이다.
  • 필터를 어디에 두느냐가 세대를 나눈다. 2020 EBR은 필터를 인덱스 질의문 안에, 2020 Instagram 글은 질의 언어 안에, 2025 SilverTorch는 GPU 커널 안에 넣었다 확인(위 세 출처). X가 payload 필터를 ANN 호출에 붙이는 것과 같은 문제를 세 번 다르게 푼 셈이다.
  • 서빙 비용 제약이 모델 구조를 지정하는 경우가 있다. Instagram이 2023 Explore에서 two-tower를 고른 이유로 명시한 것은 정확도가 아니라 아이템 타워 출력이 캐시 가능하다는 점이다 확인(Instagram Explore, 2023). 자세한 인용은 instagram.md에 있다.
  • Meta 문헌에서 two-tower는 목표가 아니라 이겨야 할 baseline이다. Andromeda는 two-tower/ANN 대비로, MoL은 내적 모델과 CPU MIPS 베이스라인 대비로 성과를 서술한다 확인(계층 2, 계층 4). 반대로 X는 2025~2026에 two-tower 쪽으로 이동했다 확인(x.md). 같은 기법이 한쪽에서는 도착점이고, 다른 쪽에서는 출발점이다.
    • RankGraph 계열의 베이스라인은 Filament2, GAT-DGI, PBG, HSTU라서 two-tower/ANN 대비 진술이 아니다 확인 — arXiv 2509.02942, arXiv 2606.18379.
  • 공개 채널이 무엇을 알 수 있는지 정한다. 소스코드는 상수를 드러내고 비율을 숨긴다. 논문과 블로그는 비율(+6% recall, 23.7× RPS)을 드러내고 상수를 숨긴다. "X는 상수가 있고 Meta는 없다"가 아니라 각자 공개한 절반이 다르다. 이 노트의 X 절과 Meta 절의 문장 밀도가 다른 이유이기도 하다 추정.

Netflix를 함께 놓으면 두 개가 더 나온다.

  • retrieval 레이어의 존재는 코퍼스 크기의 함수다.
    • 수억 아이템(X OON, Meta 비연결)이면 ANN이 필수다.
    • 그래프로 제한되면(Facebook 연결) 그래프가 곧 후보 집합이다.
    • 수천에서 수만(Netflix)이면 브루트포스로 전부 채점할 수 있다.
    • "무슨 ANN 쓰세요"는 세 번째 경우에는 성립하지 않는 질문이다.
  • 콜드스타트 임베딩에는 두 극단이 있다. 버리기와 채우기다. X의 TwHIN은 참여 16회 미만이면 0벡터를 쓰고, Netflix FM은 메타데이터로 초기화한 뒤 entity age 어텐션으로 섞는다. UGC(사용자가 올린 콘텐츠)는 메타데이터가 빈약하고 아이템이 무한하다. 편성 카탈로그는 메타데이터가 풍부하고 아이템이 유한하다. 이 차이가 그대로 설계에 나타난다.

↑ 목차

누가 이걸 쓰는가

X, Instagram, Meta ads는 이 노트가 다룬 임베딩 retrieval 기법을 쓴다 확인. Facebook은 EBR을 처음 발표한 곳(검색)이지만, 연결 콘텐츠 경로에는 ANN이 등장하지 않는다 추정. TMIS 2015 기준으로 Netflix는 카탈로그 전체를 채점하고, FM 세대에 ANN을 쓰는지는 공개되지 않았다 확인(TMIS) / 관찰 2026-10-19(FM 통합 블로그). Threads는 후보 생성 방식 자체가 공개되지 않았다 관찰 2026-08-09.

  • X는 SimClusters, TwHIN, DeepRetrieval, Phoenix retrieval을 쓴다 확인 — x.md.
    • SimClusters(2020~)는 주 1회 갱신한다.
    • DeepRetrieval은 2025년의 주력이고, Phoenix retrieval은 2026년 공개 코드에 있다.
    • 인코더 계열이 공개돼 있고, 인덱스는 Qdrant/VecDB/FAISS 3계층이다.
  • Facebook은 EBR을 처음 발표한 곳(검색)이지만, 연결 콘텐츠 경로에는 ANN이 등장하지 않는다 추정 — facebook.md.
    • 피드 쪽은 unconnected 콘텐츠 비중이 11.7%(2021 Q3)에서 41.0%(2025 Q4)로 올랐고, 이 시기가 retrieval 문헌이 크게 늘어난 시기와 겹친다.
    • 연결 콘텐츠 경로에서는 팔로우 그래프가 곧 후보 집합이다.
  • Instagram은 이 저장소에서 "서빙 비용이 모델을 정했다"고 1차 출처로 말할 수 있는 유일한 사례다 확인 — instagram.md.
    • 2020년 글은 계정 임베딩 최근접 이웃(account_nn)을 쓰는 retrieval 질의 언어를 공개했다 확인. IG2Vec과 IGQL이라는 이름은 2019년 원문을 열지 못해 1차 근거가 없다 관찰 2026-08-09.
    • Explore에서는 two-tower를 쓴다(2023, 캐시 가능성이 선정 이유).
  • Meta의 계층 1~4는 지면이 서로 다르다. 광고 한정이 명시된 것은 계층 4(Andromeda와 HILL/MoNN)뿐이다 확인.
    • SilverTorch(계층 1)는 블로그가 UGC 피드와 영상 콘텐츠의 주 retrieval 시스템이라고 쓴다 확인 — SilverTorch 블로그, 2026-05-26.
    • MoL과 h-indexer(계층 2)의 논문은 Meta의 큰 추천 배포 가운데 하나에서 실험했다고만 쓰고 지면을 밝히지 않는다 확인 — arXiv 2306.04039.
    • RankGraph(계층 3)는 users·posts·ads를 함께 담는 교차 도메인 그래프이고, RankGraph-2는 Meta의 여러 지면에 배포됐다고 쓴다 확인 — arXiv 2509.02942, arXiv 2606.18379.
    • Andromeda와 HILL/MoNN을 organic feed에도 쓴다는 1차 진술은 없다 추정.
  • Threads에는 임베딩 retrieval과 ANN에 대한 진술이 하나도 없다. 후보 생성 방식 자체가 공개되지 않았다 관찰 2026-08-09 — threads.md.
    • 검사한 자료는 ig-threads-feed 카드 본문과 Threads 엔지니어링 블로그 2편이다.
  • Netflix는 TMIS 2015 기준으로 전 카탈로그를 채점한다. FM 임베딩 스토어를 일 단위로 만들어 피처와 후보에 dual-use로 쓰고, 신규 타이틀은 메타데이터로 초기화한다 확인 — netflix.md.

인덱스 재구축과 재학습 주기는 model-freshness.md에 정리돼 있다. SilverTorch, RankGraph-2의 3시간 주기, Instagram의 일 단위 아이템 타워가 여기에 해당한다. 여기서는 반복하지 않는다.

↑ 목차

아직 확인하지 못한 것

아직 확인하지 못한 것은 X 쪽 네 가지, Meta 쪽 다섯 가지다.

  • X
    • TwHIN의 프로덕션 임베딩 차원과 실제 관계 집합을 모른다. 공개된 것은 예제용 설정의 관계 4개뿐이다.
    • DeepRetrieval의 모델 구조와 손실, 음성 샘플링을 모른다. 공개된 것은 추론 호출뿐이다.
    • 레거시 HNSW ANN 서비스가 무엇을 인덱싱하는지 전체 목록을 모른다.
    • GraphJet TopSecondDegreeByCountForTweet의 점수 계산식을 모른다. 외부 프로젝트여서 VLDB 2016 p1281을 참조해야 한다.
  • Meta
    • organic feed의 소스별 후보 수를 모른다. X는 소스마다 상수가 있지만, Meta 쪽은 Facebook과 Instagram의 퍼널 총량만 공개돼 있다. 그중 임베딩 소스가 얼마인지 모른다.
    • Andromeda와 HILL/MoNN이 organic feed도 서빙하는지 모른다. 전부 ads 문헌이다. 같은 인프라를 쓴다는 진술을 찾지 못했다.
    • IG2Vec과 IGQL의 현재 상태를 모른다. 2020년 블로그 이후 언급이 없고, 원문 URL은 500을 반환한다(2026-08-09 실측). 폐기됐는지 이름만 바뀌었는지 알 수 없다.
    • SilverTorch의 인덱스 갱신 지연을 모른다. 처리량과 TCO 수치는 있지만, "새 아이템이 몇 초 만에 검색 가능해지는가"는 없다.
    • radius mode를 아직도 쓰는지 모른다. 2020 EBR의 핵심 선택인데, 이후 문헌에 radius라는 단어가 다시 나오지 않는다.

↑ 목차

출처

X

  • twitter/the-algorithm — 2025-09-03 커밋 c54bec0, 공개 소스코드. simclusters_v2/, simclusters-ann/, ann/, tweet-mixer/를 참조했다.
  • twitter/the-algorithm-ml — 2023, 공개 소스코드. projects/twhin/를 참조했다.
  • xai-org/x-algorithm — 2026, 공개 소스코드 (Apache 2.0).
  • SimClusters — KDD 2020 논문. simclusters_v2/README.md:9에서 인용했다. 레포에 재현되지 않은 수치는 논문에만 있다.

Meta — 인덱스 계층

Netflix

Meta — 서비스 쪽 근거 (인용 원문은 서비스 노트에 있다)

  • Scaling the Instagram Explore recommendations system — 2023-08-09, 블로그. two-tower를 아이템 타워 캐시 가능성 때문에 골랐다는 진술이 있다.
  • Designing a Constrained Exploration System — 2020-12-10, 블로그. retrieval 질의 언어의 쿼리 예시가 있다. 글에는 IGQL이라는 이름이 없다. ⚠ engineering.fb.com에 다른 제목으로 중복 게재됐다.
  • The AI behind unconnected content recommendations — 2023, 블로그. billions → thousands → hundreds 퍼널을 서술한다.
  • ⚠ IG2Vec과 IGQL 명칭의 1차 원문(2019 "Powered by AI")은 2026-08-09 기준 HTTP 500을 반환한다. 이 노트는 그 글을 근거로 쓰지 않았다. 관찰 2026-08-09 (요청해 본 URL 3건)

↑ 목차