Skip to Content
Backend두 글자 회사명 검색을 SQLite에서 처리하기
💻 Backend2026년 10월 13일

두 글자 회사명 검색을 SQLite에서 처리하기

#sqlite#fts5#search#company-lens
Company Lens 데이터 적재와 검색2 / 2
Company Lens에서 최신 사업장 검색과 두 글자 검색어를 보완했습니다. FTS5 trigram의 제약과 보조 인덱스, 검색 후보 검증 방식을 정리합니다.

Company Lens 검색에는 두 가지 문제가 있었습니다. 기본 결과에 과거 사업장이 함께 섞였고, 짧은 검색어는 처리하기 어려웠습니다. 결과가 넓어지면 원하는 회사를 찾기 어렵고 조회 비용도 커졌습니다.

최신 자료를 찾는 기본 검색과 과거 이력 접근을 구분한 뒤, 두 글자 검색을 위한 보조 경로를 추가했습니다.

최신 적재 자료 검색

기본 검색 대상은 최신 적재월에 있는 사업장으로 정하고 가입자 수순으로 보여줬습니다. 과거 자료는 별도 옵션으로 검색할 수 있게 했습니다.

최신 자료에 없다는 이유로 상세 페이지나 과거 이력을 지우지는 않았습니다. 해당 월에 자료가 없는 상태를 폐업으로 판단할 수도 없습니다. 검색 결과의 기본 범위를 줄이는 것과 데이터를 보존하는 일은 분리했습니다.

짧은 검색어와 trigram의 한계

초기 검색에는 FTS5의 trigram tokenizer를 사용했습니다. 세 글자 단위로 토큰을 만드는 방식이므로 두 글자 회사명을 같은 방식으로 처리하기 어려웠습니다.

두 글자 검색에는 보조 FTS 인덱스로 후보를 찾고, 실제 이름에 검색어가 포함되는지 부분 문자열로 다시 확인하는 처리를 더했습니다. 한 글자 검색은 지원하지 않았습니다.

변경목적
최신 사업장 조회용 지표기본 검색 대상 축소
가입자 수 인덱스기본 정렬 보완
두 글자 보조 FTS짧은 회사명 후보 조회
부분 문자열 확인검색어가 실제 포함됐는지 검증
후보 수 제한지나치게 넓은 조회 방지

인덱스는 요청마다 생성하지 않고 초기 생성 명령과 이후 적재 과정에서 관리했습니다. 이름의 법인 표기와 공백을 고려하는 관련도 정렬도 별도로 유지했습니다.

두 글자를 별도 토큰으로 만드는 코드

실제 lib/company-short-search.ts에서는 두 글자 묶음을 UTF-8의 16진수 문자열로 바꿔 FTS 토큰에 넣습니다. 다음은 원본의 토큰 생성 부분을 정리한 코드입니다.

javascript
example/company-bigrams.js
const asciiLower = value => value.replace(/[A-Z]/g, letter => letter.toLowerCase()); const token = value => `b${Buffer.from(value).toString('hex')}`; export function shortSearchTokens(...values) { const terms = new Set(); for (const value of new Set(values.map(value => asciiLower(value ?? '')))) { const chars = [...value]; for (let i = 0; i + 1 < chars.length; i++) { terms.add(token(chars[i] + chars[i + 1])); } } return [...terms].join(' '); }

예를 들어 “가나다”에서는 “가나”와 “나다”를 만들 수 있습니다. 문자를 펼쳐 순회하므로 UTF-16 코드 단위로 한 글자를 반으로 자르는 방식과도 구분됩니다. 같은 토큰은 Set으로 한 번만 넣습니다. 이는 검색 후보를 찾기 위한 자료이고 최종 회사명을 새로 정규화해 바꿔 저장한다는 뜻은 아닙니다.

원본은 회사명 보조 검색 소스 에서 볼 수 있습니다. 세 글자 이상 경로는 기존 trigram을 유지하며, 두 글자 경로의 후보는 실제 부분 문자열 조건으로 다시 확인합니다.

인덱스 준비와 넓은 검색 처리

검색 인덱스는 HTTP 요청 중에 전체를 다시 만들지 않습니다. 저장소에는 두 인덱스를 함께 준비하는 명령과 짧은 검색용 인덱스만 추가하는 명령이 있습니다.

bash
example/prepare-company-search.sh
# 저장소와 데이터베이스를 준비한 개발·관리 환경에서 실행합니다. npm run search:rebuild # 기존 DB에 짧은 검색 인덱스만 보완할 때의 별도 명령 npm run search:rebuild-short

두 명령을 매번 이어 실행해야 한다는 뜻은 아닙니다. 데이터베이스 상태에 맞춰 선택하고, 실제 적재에서는 SQL 트리거로 변경된 이름과 번호의 토큰을 유지합니다. 인덱스 유무가 불명확한 상태에서 조회 성능만 비교하지 않도록 했습니다.

현재 소스의 후보 제한은 20,000건입니다. 이 값은 최종 화면의 페이지 크기가 아니라 필터·정렬 전에 읽는 후보의 폭을 제한합니다. 따라서 limit=5로 작게 요청해도 지나치게 넓은 검색어가 자동으로 저렴해지는 것은 아닙니다. 제한에 걸리면 더 구체적인 회사명이나 공개 번호를 요청하도록 오류를 반환합니다.

경로먼저 줄이는 범위이후 확인
기본 검색최신 적재 자료필터·정렬·페이지
두 글자 검색보조 FTS 후보실제 문자열 포함
넓은 검색후보 개수 제한입력을 좁히도록 안내

인덱스를 추가한 뒤에는 기존 검색 조건과 결과가 유지되는지도 확인했습니다. 응답 시간을 수치로 비교한 결과는 이 글에 포함하지 않았습니다.

검색 조건을 유지한 성능 개선

검색을 빠르게 만드는 동안 기존 조건의 의미가 달라지지 않는지도 확인했습니다. 예를 들어 일용 사업장은 자료에 표시된 사업장 구분값으로 판단했습니다. 회사명에 ‘일용’이라는 단어가 있다는 이유만으로 제외하지 않았습니다.

회사 상세와 비교 API의 입력 규칙도 함께 맞췄습니다. 검색 인덱스는 후보를 찾는 도구이고, 어떤 대상을 보여줄지는 서비스가 정한 조건에 따라 결정하도록 했습니다.

FTS를 사용해도 모든 필터와 정렬이 빨라지는 것은 아닙니다. 후보 수 제한은 유지하면서 검색 결과와 기존 상세 페이지 접근을 확인했습니다. 검색 대상과 짧은 검색어 처리를 각각 바꾼 것이지, 모든 조회를 하나의 인덱스로 해결한 구성은 아닙니다.

참고 자료

Last updated on