Skip to content

feat(S15P11A705-339): 단어형 질의의 본문 문자열 검색과 RRF 병합 (검증 게이트 통과) - #206

Merged
colosair merged 10 commits into
devfrom
search-upgrade
Aug 7, 2026
Merged

feat(S15P11A705-339): 단어형 질의의 본문 문자열 검색과 RRF 병합 (검증 게이트 통과)#206
colosair merged 10 commits into
devfrom
search-upgrade

Conversation

@colosair

@colosair colosair commented Aug 7, 2026

Copy link
Copy Markdown
Member

요약

검색 고도화 트랙의 back 몫을 dev 에 반영한다. 본문에 질의 문자열이 그대로 있는 기록을 찾아 벡터 결과와 합치는 경로를 추가했다. 기본 꺼짐 플래그 뒤에 있어 이 병합으로 검색 동작은 바뀌지 않는다.

3레포(docs·back·ai)를 같은 이름의 통합 브랜치에서 함께 준비해 한 번에 릴리스한다. docs 계약 개정(3c28c01)은 병합 완료, aiai#118 로 함께 올라가 있다.

Jira

변경 사항

  • LexicalContextRepository(신설) — core.context 에서 요청자 소유·삭제되지 않은 본문의 부분일치를 찾는다. 기록당 대표 Context 하나를 고르고, LIKE 문법 글자(%·_·\)는 이스케이프해 글자로 취급한다.
  • LexicalSearchProperties(신설) — pinlog.search.lexical.enabled(기본 false) · word-query-max-chars(기본 5, ai 의 같은 뜻 설정과 일치해야 한다).
  • RecordSearchService — FastAPI 응답을 기록 단위로 정리한 직후 병합 단계를 넣었다. 단어형 질의에서만 문자열 매치를 조회해 RRF(k=60)로 재정렬하고, size 절단은 재정렬 뒤 한 번만 한다. 문자열 후보도 기존 Core 재검증을 그대로 지난다.
  • backend-ci.yml — 통합 브랜치를 트리거에 추가(검색 고도화 작업 PR 의 base 가 dev 가 아니었다).
  • IntegrationContainerSupport — 테스트 컨테이너 postgres 연결 한도 상향. 컨텍스트가 늘며 기본 한도(100)를 넘겨 기동이 실패했다.
  • 문서 — 구현 리포트 BI-43, 작업 로그.

검증

  • 테스트 우선으로 진행 — 신규 12건 중 병합을 요구하는 6건이 구현 전 실패(RED)함을 확인한 뒤 구현, 전건 통과(GREEN)
  • 회귀 — ./gradlew clean check --no-daemon 통과. RecordSearchApiTests 에 「기본값 꺼짐 = 현행 동일」 계약 1건 추가
  • 검증 게이트 5기준 전량 통과 — back+ai 를 함께 띄워 사용자와 같은 경로(쿠키 인증·CSRF 포함)로 측정. 특히 신한 회복은 이 문자열 경로의 몫이며 전체 경로에서 실증했다. 증거는 ai 레포 .search/gate_*.json

리뷰 포인트

  1. 기본 꺼짐이 안전 근거다. 플래그가 false 인 상태가 현행과 동일함을 계약 테스트와 게이트 기준 ④가 이중으로 고정한다.
  2. 문자열 단독 항목의 similarity 는 0.0 이다. 벡터 컷을 통과하지 못해 실을 코사인이 없다. 응답 계약상 숫자가 필수이고(front 스키마), 0.0 은 실제 코사인이 만들 수 없는 값이라 구분 표지도 된다. 벡터 후보의 값은 원 코사인 그대로다.
  3. 실측을 런타임에 그대로 옮길 수 없던 3지점(문자열 목록의 순위 기준·문자열 단독 후보의 점수 항·similarity 대체값)의 판단과 근거는 BI-43 에 적었다. 전부 「컷 탈락 후보의 코사인이 FastAPI 밖으로 나오지 않는다」에서 나온 제약이다.
  4. 병합 방식은 merge commit 이다. 통합 브랜치에 여러 작업이 쌓여 있어 squash 하면 단위별 이력이 사라진다. 조직 표준이 squash 를 「GitHub 이 강제하지 않는 운영 convention」으로 분류한다.

미결 / 후속

  • 이 병합은 운영 배포를 유발한다(이미지 발행 → infra 자동 갱신 → Argo CD). 플래그가 꺼져 있어 동작은 불변이지만, 되돌릴 때는 dev revert PR 이 유일한 정상 경로다(infra values 만 되돌리면 자동화가 다시 앞으로 민다).
  • 문자열 매치의 의미 검증(어절 중간 시작 일치·동형어)은 이 코퍼스에서 사례를 만들 수 없어 운영 데이터 재평가 조건으로 남는다.

🤖 Generated with Claude Code

colosair and others added 10 commits August 6, 2026 14:04
검색 고도화 트랙(ai 레포 P49 §6)의 작업 PR은 base가 dev가 아니라 통합 브랜치라서,
트리거가 dev 한정이면 그 PR들이 CI 없이 병합된다. ai-ci가 같은 이유로 같은 트리거를
추가한 선례(ai cf07b15)를 따른다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Spring 테스트 컨텍스트 캐시는 컨텍스트를 닫지 않고 쌓고, 컨텍스트마다 HikariPool(기본 10)이
공유 컨테이너 하나에 연결을 잡는다. 합이 postgres 기본 한도(100)를 넘으면 늦게 뜨는 컨텍스트가
"FATAL: sorry, too many clients already"로 죽는다 — 검색 쪽 컨텍스트가 하나 늘면서 실제로 넘었다
(clean check에서 OpenApi·Security·Flyway 계열 4클래스 기동 실패로 관측).

캐시 상한 축소는 기각한다: evict된 컨텍스트의 재기동 비용을 뒤 클래스가 갚고, 어느 클래스가
느려지는지가 실행 순서에 좌우된다. 이 값은 테스트 전용 컨테이너 설정이라 운영과 무관하다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
검색 고도화 트랙 P49 작업 5(티켓 미발급 — 발급 시 병합 커밋에 키를 싣는다). 본문에 질의
문자열이 그대로 있는데 임베딩 유사도가 낮아 검색되지 않는 실패 사례(신한)를 회복한다.
규칙은 ai 파트 오프라인 실측(I54)의 확정안 그대로다: 단어형 한정·부분일치 게이트 +
RRF(k=60) 병합 + similarity 원 코사인 유지 + 실패 시 벡터만.

- LexicalContextRepository: core.context 본인 소유·활성 본문의 부분일치 매치.
  DISTINCT ON으로 Record당 대표 Context(최신 교체본) 하나. LIKE 특수문자 이스케이프
- LexicalSearchProperties: pinlog.search.lexical.enabled(기본 false — 꺼진 상태가 현행과
  동일하다는 계약을 기본값 컨텍스트 테스트로 고정) · word-query-max-chars(ai와 같은 값 5)
- RecordSearchService: distinctByRecord 직후 병합 단계. 단어형 판정은 ai와 등가(유니코드
  공백 전체·코드 포인트 길이). 문자열 후보도 기존 Core 재검증에 그대로 합류. 조회 실패는
  벡터 결과로 조용히 복귀. size 절단은 RRF 하위부터 한 번만
- 실측과 다르게 간 지점 셋(문자열 목록 순위 기준·문자열 단독 후보의 점수 항·similarity
  0.0)은 컷 탈락 후보의 코사인이 FastAPI 밖으로 나오지 않는 제약에서 나왔다 — 근거와
  트레이드오프는 구현 리포트(BI-42, 별도 커밋 예정)에 있다

검증: 신규 12건 RED(병합 요구 6건 실패 확인) → 구현 후 GREEN, 기본값 꺼짐 계약 1건 추가,
clean check 전체 통과.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
구현 커밋(b909227)이 예고한 기록이다. 실측(ai 레포 I54)의 계산을 런타임에 그대로 옮길 수
없던 세 지점(문자열 목록 순위 기준·문자열 단독 후보의 점수 항·similarity 대체값)의 판단과
근거, TDD 검증 경과, 실서버 E2E가 검증 게이트 몫으로 남는다는 경계를 담는다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
P49 §6 규칙의 정기 동기화다. dev 신규 커밋(f9d521f)은 AI 구역 문서 가독성
재구성으로, 이 트랙의 변경 파일과 교집합이 없음을 병합 전 확인했다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
dev에 먼저 머지된 PR #202가 BI-42를 `BI-42-2026-08-07-map-keyword-chips.md`로
확정했다. 이 브랜치의 `BI-42-2026-08-06-search-lexical-merge.md`와 번호가
겹치므로 뒤에 오는 이쪽을 BI-43으로 옮긴다. dev에 BI-43은 아직 없다.

두 파일은 날짜와 주제가 달라 파일명이 서로 다르다. git은 경로가 다른 파일을
같은 자원으로 보지 않으므로 병합할 때 충돌로 잡지 않고 둘 다 조용히 남긴다.
번호 중복은 사람이 읽을 때만 드러난다. dev의 직전 커밋 39cbc7f가 같은 사고를
BD-46에서 수습한 커밋이고, 이번에는 병합 전에 처리한다.

implements 구역은 목록 표를 두지 않으므로(`docs/backend/implements/README.md`)
파일명과 H1, 작업 로그의 링크만 고치면 참조가 모두 맞는다. 브랜치 전체에서
옛 번호를 참조하는 곳이 남지 않았음을 확인했다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
P49 §6 규칙의 정기 동기화다. dev 신규 커밋은 세 건이다. 733787d는 최근 7일
기록 목록 조회 API, f66b324는 지도 bbox 안 상위 키워드 조회 API, 39cbc7f는
겹친 BD-46 두 개 중 나중 것을 BD-50으로 옮긴 문서 정리다.

변경 파일 경로에 교집합이 없음을 병합 전에 확인했다. 문서 번호는 교집합이
있었으나 앞선 커밋 a5e7673에서 이쪽 BI-42를 BI-43으로 옮겨 미리 풀었다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
병합 직전 dev 가 전진했다(#204 이미지 업로드 용량 상향). dev 브랜치 보호가 strict 라
병합 시점에 dev 최신 상태여야 한다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
병합 직전 dev 가 또 전진했다(#203 컬렉션 목록 조회 API). 파일 교집합이 없음을
확인하고 반영한다. dev 브랜치 보호가 strict 라 병합 시점에 dev 최신이어야 한다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
dev 가 계속 전진해 strict 요건을 다시 맞춘다. 파일 교집합 없음.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@colosair
colosair merged commit 1c727a1 into dev Aug 7, 2026
4 checks passed
@colosair
colosair deleted the search-upgrade branch August 7, 2026 08:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant