Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
74f974a
chore: .env파일로 환경변수 주입하도록 변경
Dimo-2562 Feb 3, 2026
6336f74
test: 원격 DB에서 json 형태로 자료 추출하는 테스트 코드 작성
Dimo-2562 Feb 3, 2026
112d46d
test: 유저 프로필 생성 후 json으로 export하는 테스트코드 작성
Dimo-2562 Feb 3, 2026
ed2b0f5
refactor: 추천 테스트 관련 파일 test 경로 아래로 응집
Dimo-2562 Feb 3, 2026
16cae14
refactor: json으로 변환하는 메서드 별도 클래스로 분리
Dimo-2562 Feb 4, 2026
5daff8d
chore: 필요없는 코드 제거
Dimo-2562 Feb 4, 2026
b46563c
chore: 필요없는 파일 삭제
Dimo-2562 Feb 5, 2026
a2efd85
refactor: 추천 평가 setup 개선
Dimo-2562 Feb 5, 2026
28d2450
fix: json 파일의 ID값과 실제 DB의 ID 값 매칭하는 역매핑 맵 생성으로 매핑 문제 해결
Dimo-2562 Feb 5, 2026
eaf1df3
improve: 추천 판단 지표 점수를 임베딩 값 대신 LLM 기반으로 변경
Dimo-2562 Feb 5, 2026
5b85068
improve: UI에 맞게 K값 측정을 4, 8, 30으로 변경
Dimo-2562 Feb 5, 2026
a7863b4
improve: Recall과 nDCG K를 4, 8, 30을 측정하도록 변경
Dimo-2562 Feb 5, 2026
45a37ae
test: title과 summary만으로 검색하는 것이 평가지표가 좋게 나와 둘의 가중치 결정하는 테스트 추가
Dimo-2562 Feb 5, 2026
b96a104
improve: title과 summary의 가중치를 이전에 측정한 것으로 변경
Dimo-2562 Feb 5, 2026
3c4ceed
chore: 평가 테스트 결과에 따라 하이퍼 파라미터 변경사항 적용
Dimo-2562 Feb 5, 2026
cc406fc
refactor: HNSW 사용을 위해 ES 네이티브 knn으로 변경, 객체 매핑을 통한 게시글 제외 대신, 쿼리 날릴 때 적용
Dimo-2562 Feb 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,11 @@ stop-dev-tunnel.sh
/.claude

### env ###
/.env
.env

### Apple Private Keys ###
src/main/resources/keys/
*.p8
*.p8

### Test json files ###
src/test/resources/fixtures/evaluation/
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class RecommendationProperties {

private Integer mmrFinalSize = 30;

private Double lambda = 0.6;
private Double lambda = 0.95;

private Integer activeUserHours = 24;

Expand All @@ -34,9 +34,9 @@ public class RecommendationProperties {
@NoArgsConstructor
@AllArgsConstructor
public static class EmbeddingWeights {
private Float title = 0.4f;
private Float summary = 0.4f;
private Float content = 0.2f;
private Float title = 0.5f;
private Float summary = 0.5f;
private Float content = 0.0f;
}

@Getter
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,17 @@ private double calculateWeightedSimilarity(MmrCandidate candidate1, MmrCandidate
summarySim = VectorUtil.cosineSimilarity(candidate1.getSummaryVector(), candidate2.getSummaryVector());
}

// 코사인 유사도(-1.0 ~ 1.0)를 0.0 ~ 1.0 범위로 정규화하여 ES 점수와 스케일을 맞춤
double normalizedTitleSim = (titleSim + 1) / 2.0;
double normalizedSummarySim = (summarySim + 1) / 2.0;

// 가중 평균 (제목 + 요약만, 콘텐츠는 제외)
double titleWeight = weights.getTitle();
double summaryWeight = weights.getSummary();
double totalWeight = titleWeight + summaryWeight;

return (titleWeight * titleSim + summaryWeight * summarySim) / totalWeight;
if (totalWeight == 0) return 0.0;

return (titleWeight * normalizedTitleSim + summaryWeight * normalizedSummarySim) / totalWeight;
}
}

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,93 +1,50 @@
package com.techfork.global.elasticsearch.query;

import co.elastic.clients.elasticsearch._types.query_dsl.ChildScoreMode;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;

/**
* Elasticsearch 벡터 검색 쿼리 빌더 인터페이스
* script_score를 사용한 코사인 유사도 검색 쿼리 생성
*/
public interface VectorQueryBuilder {

/**
* 여러 벡터 필드를 가중치 합산하는 bool should 쿼리 생성
* (title, summary, content chunks 등을 결합)
*
* @param titleField 제목 벡터 필드명
* @param summaryField 요약 벡터 필드명
* @param contentChunksPath content chunks nested 경로
* @param chunkEmbeddingField chunk 임베딩 필드명
* @param queryVector 쿼리 벡터
* @param titleWeight 제목 가중치
* @param summaryWeight 요약 가중치
* @param contentWeight 컨텐츠 가중치
* @return 가중치 적용된 복합 쿼리
*/
Query createWeightedVectorQuery(
String titleField,
String summaryField,
String contentChunksPath,
String chunkEmbeddingField,
float[] queryVector,
float titleWeight,
float summaryWeight,
float contentWeight
);

/**
* 랜덤 시드를 포함한 가중치 벡터 쿼리 생성
* (추천 재생성 시 다양성 확보용)
*
* @param titleField 제목 벡터 필드명
* @param summaryField 요약 벡터 필드명
* @param contentChunksPath content chunks nested 경로
* @param chunkEmbeddingField chunk 임베딩 필드명
* @param queryVector 쿼리 벡터
* @param titleWeight 제목 가중치
* @param summaryWeight 요약 가중치
* @param contentWeight 컨텐츠 가중치
* @param randomSeed 랜덤 시드
* @param randomWeight 랜덤 가중치 (0.0~1.0, 보통 0.1~0.3)
* @return 랜덤 요소가 포함된 복합 쿼리
*/
Query createWeightedVectorQueryWithRandomness(
String titleField,
String summaryField,
String contentChunksPath,
String chunkEmbeddingField,
float[] queryVector,
float titleWeight,
float summaryWeight,
float contentWeight,
long randomSeed,
double randomWeight
);

/**
* 단일 필드에 대한 script_score 쿼리 생성
*
* @param fieldName 벡터 필드명
* @param queryVector 쿼리 벡터
* @param boost 부스트 가중치
* @return script_score 쿼리
*/
Query createScriptScoreQuery(String fieldName, float[] queryVector, float boost);

/**
* nested 필드에 대한 script_score 쿼리 생성
*
* @param nestedPath nested 경로
* @param vectorFieldName 벡터 필드명 (nested 내부)
* @param queryVector 쿼리 벡터
* @param boost 부스트 가중치
* @param scoreMode nested 스코어 모드 (Max, Avg 등)
* @return nested script_score 쿼리
*/
Query createNestedScriptScoreQuery(
String nestedPath,
String vectorFieldName,
float[] queryVector,
float boost,
ChildScoreMode scoreMode
);
}
package com.techfork.global.elasticsearch.query;

import co.elastic.clients.elasticsearch._types.KnnSearch;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import java.util.List;

/**
* Elasticsearch 벡터 검색 쿼리 빌더 인터페이스
* 네이티브 k-NN 검색 및 하이브리드 검색을 위한 쿼리 생성 제공
*/
public interface VectorQueryBuilder {

/**
* 네이티브 k-NN 검색 객체 리스트 생성
* (title, summary, content 필드에 대한 k-NN 검색)
*
* @param titleField 제목 벡터 필드명
* @param summaryField 요약 벡터 필드명
* @param contentField 컨텐츠 벡터 필드명 (Nested 경로 포함)
* @param queryVector 쿼리 벡터
* @param titleWeight 제목 가중치
* @param summaryWeight 요약 가중치
* @param contentWeight 컨텐츠 가중치
* @param k 검색할 이웃 수
* @param numCandidates 후보군 수
* @param filter 사전 필터링 쿼리 (null 가능)
* @return KnnSearch 객체 리스트
*/
List<KnnSearch> createKnnSearches(
String titleField,
String summaryField,
String contentField,
float[] queryVector,
float titleWeight,
float summaryWeight,
float contentWeight,
int k,
int numCandidates,
Query filter
);

/**
* 랜덤 점수를 위한 function_score 쿼리 생성
*
* @param randomSeed 랜덤 시드
* @param randomWeight 랜덤 가중치
* @return function_score 쿼리
*/
Query createRandomScoreQuery(long randomSeed, double randomWeight);
}
Loading
Loading