목차
검색은 찾는 데서 끝나지 않는다. 찾은 다음에 줄을 세워야 하고, 사실 사용자가 체감하는 검색 품질은 거의 전부 이쪽이다.
쪽 번호가 오천 개면
책 뒤의 찾아보기를 다시 펴 보자. 이런 항목이 있으면 유용하다.
격리 수준 ......... 214, 301, 302세 쪽 중 하나를 펴면 된다. 그런데 이런 항목이 있으면 어떨까.
데이터 ............ 12, 13, 14, 15, 17, 19, 22, ... (그리고 480쪽 더)이건 있으나 마나다. 찾아보기의 값이 사라진 게 아니라, 너무 많이 걸려서 어디를 펴야 할지를 다시 모르게 된 것이다.
여기서 이 비유가 한 번 깨진다. 책의 찾아보기는 사람이 만든다. 편집자가 “이건 올릴 만하다”고 판단한 낱말만 올리고, 지나가듯 나온 쪽 번호는 아예 안 적는다. 그래서 책의 찾아보기에는 480쪽짜리 항목이 애초에 없다.
역색인은 다르다. 기계가 본문의 모든 낱말을 예외 없이 넣는다. 고르는 사람이 없으니 걸러지지도 않는다. 이 글의 문제는 그래서 생긴 문제다. 책에는 없던 자리다.
흔한 낱말은 아무것도 안 좁힌다
사용자가 장바구니 오류라고 쳤다. 두 낱말의 포스팅 리스트를 꺼내 보니 이렇다.
칸 하나가 문서 하나다. 같은 결과에 들어왔어도 어느 낱말이 좁혀 준 것인지가 이만큼 다르다.
오류는 거의 모든 문서에 있다. 이 낱말이 걸러 낸 문서는 사실상 없다. 반면 장바구니는 아주 일부에만 나온다. 후보를 실제로 좁혀 준 건 이쪽 하나다.
같은 결과에 들어온 문서라도 어느 낱말 때문에 들어왔느냐가 다르다. 장바구니 때문에 들어온 문서가 오류 때문에 들어온 문서보다 훨씬 값지다.
드문 낱말이 값지다
이게 랭킹의 첫 번째 원칙이고, 사실상 절반이다.
어떤 낱말이 전체 문서 중 몇 건에 나오는지를 세어 두고, 적게 나오는 낱말일수록 점수를 크게 준다. 흔한 낱말은 점수를 거의 안 준다.
효과가 두 가지다.
- 불용어를 따로 안 지워도 된다.
그리고가 색인에 있어도 점수가 0에 가까우니 순위에 영향을 안 준다. 앞 글에서 “지우는 대신 순위에서 내린다”고 한 게 이 이야기다 - 긴 검색어가 알아서 핵심어를 찾는다. 사용자가
주문한 상품이 장바구니에서 사라지는 오류라고 통째로 쳐도, 점수가 몰리는 낱말은장바구니와사라지는쪽이다. 조사와 흔한 명사는 자기 몫만큼만 가져간다
드문 낱말이 값지다는 문장 하나가 검색 품질의 뼈대다. 나머지는 여기에 붙는 보정이다.
많이 나올수록 관련 있다, 다만 갈수록 덜
두 번째 원칙은 상식적이다. 한 문서 안에서 그 낱말이 여러 번 나오면 더 관련 있다. 장바구니가 한 번 스쳐 지나간 문서보다 열 번 나온 문서가 장바구니 이야기일 가능성이 높다.
여기에 단서가 붙는다. 횟수에 그대로 비례하게 주면 안 된다.
장바구니가 100번 나온 문서가 10번 나온 문서보다 10배 관련 있지는 않다. 둘 다 장바구니에 대한 글이고, 그 지점을 넘으면 더 나온다고 더 관련 있어지지 않는다. 그래서 점수를 줄 때 처음 몇 번은 크게 올려 주고 갈수록 덜 올려 준다.
이 보정이 없으면 무슨 일이 나느냐면, 같은 낱말을 본문 아래에 백 번 박아 넣은 문서가 1등이 된다. 실제로 그런 문서를 만드는 사람들이 있어서 생긴 보정이기도 하다.
긴 문서는 불리하게 잡는다
세 번째 보정이다. 문서가 길면 아무 낱말이나 많이 나온다.
100자짜리 문서에 장바구니가 세 번 나온 것과 10만 자짜리 문서에 세 번 나온 것은 뜻이 전혀 다르다. 앞엣것은 장바구니에 대한 글이고, 뒤엣것은 어쩌다 언급된 것이다.
그래서 등장 횟수를 그대로 쓰지 않고 문서 길이로 눌러 준다. 평균보다 긴 문서는 점수를 깎고, 짧은 문서는 덜 깎는다.
이 보정에도 부작용이 있다. 지나치게 세게 걸면 내용 없는 짧은 글이 위로 올라온다. 제목만 있고 본문이 두 줄인 문서가 긴 정리 글을 이기는 식이다. 그래서 이 눌러 주는 정도는 손잡이로 빼 두고 서비스에 맞춰 조절한다.
점수는 낱말만 보지 않는다
여기까지가 본문 낱말만 보고 매기는 점수다. 실제 서비스는 여기에 다른 신호를 더 얹는다.
어디에 나왔는지. 제목에 장바구니가 있는 문서와 본문 끝자락에 있는 문서는 다르다. 필드마다 가중치를 다르게 준다. 대개 제목·태그가 본문보다 무겁다.
언제 쓰였는지. 뉴스나 공지처럼 최신성이 중요한 데이터는 오래된 문서의 점수를 깎는다. 반대로 문서 아카이브라면 최신성이 아무 의미가 없다.
사람들이 무엇을 골랐는지. 같은 검색어에서 사람들이 많이 클릭한 문서를 올려 준다. 강력하지만 스스로를 강화하는 성질이 있어서, 한번 위에 오른 문서가 계속 위에 남는 쪽으로 굳는다.
완전히 일치하는지. 아이폰 15를 검색했을 때 두 낱말이 실제로 붙어 있는 문서를 위로 올린다. 자리 정보를 색인에 넣어 뒀기 때문에 할 수 있는 일이다.
신호를 더할수록 순위가 좋아지는 게 아니다. 신호가 예닐곱 개를 넘어가면 왜 이 문서가 3등인지 아무도 설명하지 못하는 상태가 된다. 그러면 순위가 이상할 때 무엇을 만져야 할지도 모르게 된다. 손잡이는 적을수록 좋고, 새 신호를 넣을 때는 그것 하나만 넣고 결과가 어떻게 변하는지 봐야 한다.
랭킹이 무너지는 자리
점수를 잘 매겨도 안 되는 질의들이 있다. 유형이 대체로 정해져 있다.
낱말 하나짜리 검색. 노트북이라고만 치면 좁혀 줄 정보가 없다. 이건 랭킹으로 풀 문제가 아니라 필터·카테고리·자동완성으로 사용자에게 낱말을 더 받아야 하는 문제다.
다른 말로 같은 것을 부를 때. 노트북과 랩탑, 핸드폰과 휴대폰. 색인에는 다른 낱말이니 서로를 못 찾는다. 동의어 사전을 따로 만들어 넣어야 하고, 그 사전은 손으로 채우는 물건이라 계속 자란다.
오타. 장바구미는 어떤 문서에도 없다. 글자 몇 개가 다른 낱말까지 후보로 넣어 주는 기능을 따로 붙여야 한다.
질의가 낱말이 아니라 의도일 때. 환불 어떻게 해요에서 사용자가 원하는 건 환불이 많이 나온 문서가 아니라 환불 방법을 알려 주는 문서다. 낱말 빈도만 보는 랭킹의 한계가 여기서 뚜렷하다.
실무에서: 랭킹은 한 번에 정하지 않는다
랭킹 작업이 다른 작업과 다른 점이 하나 있다. 맞고 틀림이 코드에 없다. 순위가 좋은지 나쁜지는 사용자만 안다.
그래서 순서가 이렇게 된다.
먼저 재현 가능한 판정 기준을 만든다. 실제 검색어 스무 개쯤을 골라 “이 검색어에는 이 문서가 위에 와야 한다”를 사람이 적어 둔다. 손잡이를 만질 때마다 이걸 돌려 본다. 이게 없으면 어제 고친 게 오늘 좋아진 건지 나빠진 건지 아무도 모른다.
그다음 로그를 본다. 검색 로그는 랭킹을 고칠 유일한 실마리다. 특히 두 가지를 본다. 결과가 0건인 검색어는 색인이나 토큰화 쪽 문제이고, 결과는 나왔는데 아무도 클릭하지 않은 검색어는 랭킹 문제다. 둘은 고칠 자리가 완전히 다르다.
손잡이는 하나씩 만진다. 제목 가중치와 최신성 감점을 같이 올리면 결과가 좋아져도 어느 쪽 덕인지 모른다.
그리고 성능 쪽으로 하나. 5,000건에 점수를 매겼다고 5,000건을 전부 정렬하지는 않는다. 상위 10개만 필요하므로 우선순위 큐로 10칸짜리 자리를 두고 지나가는 문서를 밀어 넣기만 한다. 전부 줄 세우는 것과 비용이 다르다.
정리
- 역색인은 기계가 모든 낱말을 넣기 때문에 결과가 너무 많이 걸린다. 랭킹은 그래서 생긴 문제다.
- 첫 번째 원칙이자 절반은 드문 낱말이 값지다는 것이다. 흔한 낱말은 아무것도 안 좁히니 점수를 거의 안 준다.
- 한 문서에 여러 번 나오면 더 관련 있지만, 갈수록 덜 올려 준다. 안 그러면 낱말을 박아 넣은 문서가 이긴다.
- 긴 문서는 불리하게 잡는다. 길면 아무 낱말이나 많이 나오기 때문이다.
- 실제 서비스는 여기에 제목 가중치·최신성·클릭을 얹는다. 손잡이가 늘수록 왜 그 순서인지 설명하기 어려워진다.
- 랭킹은 코드로 맞고 틀림을 못 가린다. 판정 기준을 먼저 만들고, 로그를 보고, 손잡이를 하나씩 만진다.
지금까지는 색인이 이미 만들어져 있다고 전제했다. 다음 글에서 그 전제를 걷는다. 방금 쓴 글이 검색에 안 뜨는 일은 버그가 아니라 역색인이라는 구조가 원래 그렇게 생긴 결과다.