전체 파이프라인 로직
스크립트는 한국어 키워드 목록을 입력받아 각 키워드를 관련 검색 제안어로 풍부하게 확장하고, 관련성에 따라 점수를 매긴 뒤 결과를 저장합니다.
1단계 — 입력
프론트엔드에서 { "words": ["바둑이", "서울 맛집", ...] } 형식의 JSON 데이터를 POST 방식으로 전송합니다. PHP는 이를 읽고 유효성을 검사한 뒤, 각 키워드를 하나씩 순서대로 처리합니다.
2단계 — 제안어 수집 (키워드당 4가지 소스)
각 키워드에 대해 네 곳에서 제안어를 수집합니다.
Yandex 제안 은 suggest.yandex.ru에 uil=ko(한국어 컨텍스트) 파라미터로 쿼리합니다. 실제로 Yandex는 한국어 검색에 대한 데이터가 거의 없기 때문에 이 소스에서 얻을 수 있는 결과는 많지 않지만, 비용이 거의 들지 않아 포함시켜 둡니다.
Naver 직접 조회 는 ac.search.naver.com에 키워드를 그대로 전달합니다. 이것이 핵심 소스입니다. 네이버는 한국 최대 검색 엔진으로, 자동완성 결과가 실제 한국어 검색 패턴을 잘 반영합니다. 예를 들어 바둑이를 입력하면 바둑이 룰, 바둑이 강아지 등이 반환됩니다.
Naver 자음 확장 은 새로 추가된 레이어입니다. 한국어 자음 14개를 이용해 바둑이 ㄱ, 바둑이 ㄴ ... 바둑이 ㅎ처럼 자음 힌트를 붙인 쿼리를 Naver에 각각 전송합니다. Naver는 자음 힌트를 다음 단어의 첫 글자로 인식하여, 단순 직접 조회에서는 나타나지 않는 바둑이 게임, 바둑이 뜻, 바둑이 분양 같은 제안어를 반환합니다. 속도 제한을 피하기 위해 각 호출 사이에 80ms의 대기 시간을 둡니다.
N-그램 확장 은 키워드를 공백 기준으로 분리하여 2~3 토큰으로 이루어진 모든 부분 구문을 생성합니다. 바둑이처럼 단일 단어일 경우 최소 2토큰 조건을 충족하지 못해 아무것도 생성되지 않습니다. 하지만 서울 맛집 추천이라면 서울 맛집과 맛집 추천이 생성되고, 각 구문으로 Yandex와 Naver를 다시 조회하여 전체 키워드가 아닌 일부에 기반한 제안어까지 수집합니다.
3단계 — 병합 및 중복 제거
네 소스의 결과를 하나의 배열로 합친 뒤 array_unique로 중복을 제거합니다. 이 시점에서 키워드 하나당 50~100개 이상의 원시 제안어가 존재할 수 있습니다.
4단계 — 필터링
각 제안어는 두 가지 기준을 통과해야 합니다.
불용어 필터 는 다운로드, 무료, 사진, 동영상, 인스타그램, 유튜브 등의 단어가 포함된 항목을 제거합니다. 이런 키워드는 미디어나 탐색 목적의 쿼리로, 검색 마케팅 관점에서 가치가 없습니다.
최소 토큰 필터 는 단일 단어 결과를 제거합니다. 살아남으려면 최소 하나의 공백이 포함된 복합 구문이어야 합니다. 이를 통해 Naver가 키워드 자체를 제안어로 반환하는 경우 등의 노이즈를 걸러냅니다.
5단계 — 점수 산정 및 정렬
살아남은 각 제안어는 원본 키워드와의 유사도를 기준으로 점수를 받습니다. PHP 내장 함수인 similar_text()와 levenshtein()은 바이트 단위로 동작하기 때문에, 한국어처럼 한 글자가 UTF-8에서 3바이트를 차지하는 경우 오작동합니다. 따라서 멀티바이트를 올바르게 처리하는 함수를 별도로 사용합니다.
mb_similar_score 는 원본 키워드와 제안어 사이의 공통 유니코드 문자 수를 두 문자열 전체 길이에 대한 비율로 계산합니다. 공통 문자가 많을수록 높은 점수를 받습니다.
mb_length_penalty 는 원본과 제안어의 문자 수 차이만큼 점수를 소폭 감점합니다. 지나치게 긴 제안어보다 짧고 핵심적인 제안어를 우대하는 효과가 있습니다.
최종 공식은 점수 = 유사도 × 1.5 − 길이 패널티 × 0.1이며, 점수 내림차순으로 정렬하여 원본과 가장 유사한 제안어가 상위에 오도록 합니다.
6단계 — 출력
각 키워드의 최종 정렬된 제안어 목록은 서버의 /PALS/suggests/ 폴더에 타임스탬프가 붙은 .txt 파일로 저장되고, 전체 결과가 JSON 형식으로 브라우저에 반환됩니다. 프론트엔드는 키워드별로 제목과 제안어 목록을 렌더링하고, 저장된 파일의 다운로드 링크를 제공합니다.