GN⁺: 파이썬 80줄로 만든 검색 엔진
(alexmolas.com)파이썬으로 만든 80줄짜리 검색 엔진
- 지난 9월에 Wallapop의 검색 데이터 과학자로 합류하여 Solr이라는 오픈 소스 검색 엔진을 다루는 일을 함.
- 검색 엔진의 기본 원리를 이해하고자 파이썬을 사용하여 처음부터 검색 엔진을 만들기로 결정함.
- 목표는 "소규모 웹사이트 발견성 위기"를 해결하는 것으로, 구글과 같은 검색 엔진을 사용하여 찾을 수 없는 작은 웹사이트들을 다시 위대하게 만드는 것임.
- 이 글에서는 파이썬을 사용하여 검색 엔진을 만드는 과정을 안내하며, 작성한 모든 코드는 GitHub의 microsearch 리포지토리에서 확인할 수 있음.
- 구현된 검색 엔진은 생산 준비가 완료된 검색 엔진이 아니라, 검색 엔진이 내부적으로 어떻게 작동하는지 보여주는 사용 가능한 장난감 예제임.
microsearch
- microsearch를 구성하는 요소들을 살펴보고 각 요소를 어떻게 만들었는지 탐구함: (1) 크롤러, (2) 역 인덱스, (3) 순위 매기기, (4) 인터페이스.
크롤러
- 검색 엔진을 만들기 위한 첫 번째 단계는 검색할 데이터를 확보하는 것임.
- "로컬 구글"을 만들고자 하는 의도로 팔로우하는 블로그의 데이터를 사용하여 검색 엔진을 구축함.
- 크롤링은 특정 블로그 목록의 모든 포스트를 다운로드하고 정리하는 과정을 포함함.
- 더 빠르게 하기 위해 asyncio 파이썬 라이브러리를 사용하여 크롤링 시간을 20분에서 20초로 단축함.
- 642개의 RSS 피드를 사용하였으며, 이 중 약 100개는 자주 읽는 블로그이고 나머지 500개는 surprisetalk 블로그 프로젝트에서 가져옴.
역 인덱스
- 역 인덱스는 키워드를 문서에 매핑하는 데이터 구조로, 특정 단어가 나타나는 문서를 쉽게 찾을 수 있게 함.
- 사용자가 쿼리를 검색할 때 역 인덱스를 사용하여 쿼리의 키워드와 일치하는 모든 문서를 검색함.
- 역 인덱스의 논리는 SearchEngine이라는 클래스 내에 정의되어 있으며, 두 개의 사전을 초기화하여 구현함.
순위 매기기
- 주어진 쿼리에 대해 일치하는 문서 세트가 있으면 이를 정렬하는 방법이 필요함.
- 가장 유명한 순위 매기기 방법은 구글의 PageRank이지만, BM25와 같이 내용을 기반으로 문서를 순위 매기는 다른 옵션도 존재함.
- BM25 점수 계산 방법을 포함하여 SearchEngine 클래스의 누락된 부분을 구현함.
인터페이스
- 검색 엔진을 구축한 후에는 이를 어떤 방식으로든 공개하고 싶음.
- FastAPI 앱을 구축하여 검색 엔진을 노출하는 엔드포인트를 제공하고, 검색을 수행할 수 있는 간단한 웹페이지를 렌더링함.
- 출력을 쉽게 읽을 수 있도록 상위 N개의 URL만 선택하기로 결정함.
누락된 기능
- 검색 엔진을 자주 다루는 독자라면 구현에서 많은 기능이 누락되었다는 것을 알 수 있음.
- 쿼리 연산자, n-gram 인덱싱, 쿼리 또는 문서 확장, 크롤링과 인덱싱을 동시에 수행하는 기능 등이 누락되어 있음.
결론
- 이 프로젝트를 진행하며 Solr의 내부 작동 방식에 대해 더 잘 이해하게 되었고, 비동기 코드 작성의 놀라움을 배움.
- 개인 검색 엔진을 만들기 위한 다음 단계로 검색 엔진에 의미 검색 기능을 구현할 계획임.
GN⁺의 의견
- 이 글에서 가장 중요한 것은 소규모 웹사이트의 발견성을 개선하기 위해 개인이 직접 검색 엔진을 만들 수 있다는 점임.
- 파이썬과 오픈 소스 라이브러리를 활용하여 복잡한 기능을 가진 검색 엔진을 단순화하여 구현한 경험은 초급 소프트웨어 엔지니어에게도 영감을 줄 수 있음.
- 비동기 프로그래밍의 효율성과 데이터 구조의 중요성을 실제 예제를 통해 보여줌으로써, 이 글은 기술적 통찰력과 실용적인 학습 기회를 제공함.
Hacker News 의견
-
Pandas를 이용한 BM25 검색 엔진 개발
- 개발자가 Pandas에서 작동하는 빠른 BM25 검색 엔진을 개발 중임.
- Pandas를 사용하는 이유는 BM25 알고리즘 외에도 최신성, 인기도 등 다른 요소들을 쉽게 결합할 수 있기 때문.
- 문구 매칭에는 많은 예외 사례가 있으며, 가능한 한 적은 메모리를 사용하여 위치 정보를 압축하는 것이 중요함.
-
코드 리뷰:
SearchEngine
클래스-
k1
과b
라는 파라미터의 의미를 모르겠으며, 코드에 주석이 전혀 없음. -
_documents
는 URL을 키로, 해당 URL의 내용을 값으로 가질 것으로 추정. - 코드에 문서화가 잘 되어 있지 않아 아쉬움. 문서화가 잘 되어 있었다면 검색 엔진 구축 학습 자료로 유용할 수 있었을 것.
-
-
검색 엔진의 복잡성
- 검색 엔진의 주된 어려움은 데이터의 양을 다루는 것임.
- 로직 자체는 의외로 간단하며, 프로젝트는 불필요한 부분을 대부분 제거하여 성공적임.
- 검색 엔진을 크게 만드는 것이 아니라 데이터를 더 작게 만들거나 신호 대 잡음 비율을 높이는 접근이 중요함.
-
코드 행 수에 대한 의견
- 외부 의존성을 사용하는 상황에서 코드 행 수를 자랑하는 것의 의미에 의문을 제기함.
- 코드베이스에 대한 SI 단위는 없지만, 인지 부하를 어떻게든 측정해야 한다는 의견.
-
코드 내의 표현에 대한 농담
- 코드 내의
chunk for chunk in chunks if chunk
표현을 보고 나무꾼에 관한 농담이 떠오름.
- 코드 내의
-
추천 엔진 코드 예시
- 검색 엔진과 함께 사용할 수 있는 파이썬으로 작성된 20줄 미만의 추천 엔진 코드 제공.
- 세션 로그에서 클릭된 URL을 기반으로 추천을 생성함.
- 로그에 입력된 쿼리와 클릭된 URL을 혼합하여 사용하면 맞춤법 검사 제안도 얻을 수 있음.
-
파싱 라이브러리 성능 비교
-
lxml.html
과lxml.html.clean
이BeautifulSoup
보다 훨씬 빠를 수 있음을 언급함.
-
-
키워드 사용에 대한 조언
- 영어 검색 결과의 품질을 높이기 위해 1-gram 대신 2-gram과 3-gram을 사용할 것을 권장함.
- n-gram은 문맥을 유지하는 데 도움이 됨.
-
교육적인 프로젝트에 대한 의견
- 프로젝트가 매우 멋지고 교육적이지만, 실제 배포는 하지 말 것을 권함.
- 몇 만 개의 문서를 다루는 더 큰 규모의 프로젝트에는 SQLite의 FTS5를 사용하는 것이 해답임.
-
파이썬을 이용한 대규모 데이터 처리에 대한 의문
- 대규모 데이터를 빠르게 처리해야 하는 작업에 파이썬(느린 언어)을 사용하는 것이 정말 좋은 생각인지에 대한 의문 제기.