Apache Lucene에서 영감을 받은 Tantivy 풀텍스트 검색 엔진 라이브러리
(github.com/quickwit-oss)- Tantivy는 Rust로 작성된 빠른 풀텍스트 검색 엔진 라이브러리로, 완성형 검색 서버가 아니라 검색 엔진을 만들 때 쓰는 crate에 가까움
- 설계는 Apache Lucene에서 강하게 영감을 받았으며, Elasticsearch나 Apache Solr의 대안 서버를 찾는 경우에는 Tantivy 위에 구축된 분산 검색 엔진 Quickwit을 확인하라고 안내함
- 기능은 풀텍스트 검색, BM25 점수화, 자연 질의어, 구문 검색, 증분 인덱싱, 멀티스레드 인덱싱, mmap 디렉터리, SIMD 정수 압축, 패싯 검색, JSON 필드, 집계 Collector 등을 포함함
- 안정 Rust에서 동작하고 Linux, macOS, Windows를 지원하며, 시작 시간이 10ms 미만이라 커맨드라인 도구에 적합하다고 밝힘
- 분산 검색은 Tantivy의 범위 밖이며, 문서 수정은 기존 문서를 삭제하고 다시 인덱싱해야 하고, 새 문서는
commit이후IndexReader재로드와 새Searcher획득을 거쳐 검색 가능함
Tantivy의 위치와 설계
- Tantivy는 Rust로 작성된 빠른 풀텍스트 검색 엔진 라이브러리임
- Elasticsearch나 Apache Solr처럼 바로 실행하는 검색 엔진 서버가 아니라, 그런 검색 엔진을 만들 때 사용할 수 있는 crate임
- 설계 면에서는 Apache Lucene에 더 가깝고, Lucene의 설계에서 강하게 영감을 받음
- Elasticsearch나 Apache Solr의 대안을 찾는 경우에는 Tantivy 위에 구축된 분산 검색 엔진 Quickwit을 확인하라고 안내함
성능과 벤치마크
- Tantivy는 쿼리와 컬렉션 유형별 성능을 나눈 benchmark를 제공함
- 벤치마크 결과는 쿼리의 성격과 부하에 따라 달라질 수 있음
- 벤치마크 세부 정보는 search-benchmark-game 저장소에서 확인할 수 있음
- FAQ 기준으로, 검색 지연 시간 벤치마크에서 Tantivy는 Lucene보다 평균적으로 약 2배 빠름
검색·인덱싱 기능
-
검색 기능
- 풀텍스트 검색
- Lucene과 같은 BM25 점수화
- 자연 질의어 지원:
(michael AND jackson) OR "king of pop" - 구문 검색 지원:
"michael jackson" - 범위 쿼리
- 패싯 검색
- JSON Field
- Aggregation Collector: histogram, range buckets, average, stats metrics
-
인덱싱 기능
- 증분 인덱싱 지원
- 멀티스레드 인덱싱 지원
- 영어 Wikipedia 인덱싱은 데스크톱에서 3분 미만이 걸린다고 밝힘
- 선택적 term frequency와 position indexing을 통한 인덱싱 설정 가능
- LogMergePolicy with deletes 지원
- Searcher Warmer API 제공
-
저장과 필드
- mmap directory 지원
- u64, i64, f64의 single-valued 및 multivalued fast fields 지원
&[u8]fast fields 지원- text, i64, u64, f64, dates, ip, bool, hierarchical facet fields 지원
- 문서 저장소 압축은 LZ4, Zstd, None을 지원함
토크나이저와 언어 지원
- 토크나이저는 설정 가능하며, 17개 라틴어 계열 언어에 대해 stemming을 사용할 수 있음
- 서드파티 토크나이저 지원도 제공함
- 중국어: tantivy-jieba, cang-jie
- 일본어: lindera, Vaporetto, tantivy-tokenizer-tiny-segmenter
- 한국어: lindera와 lindera-ko-dic-builder
- Tantivy용 토크나이저를 구현할 때는
tantivy-tokenizer-apicrate에 의존해야 함
실행 환경과 시작 방법
- Tantivy는 stable Rust에서 동작함
- 지원 운영체제는 Linux, macOS, Windows임
- 시작 시간이 10ms 미만이라 커맨드라인 도구에 적합함
- 시작 자료
- Tantivy의 simple search example
- tantivy-cli and its tutorial: 검색 엔진 생성, 문서 인덱싱, CLI 또는 REST API가 있는 작은 서버를 통한 검색을 쉽게 해주는 실제 커맨드라인 인터페이스
- Reference doc for the last released version
- 로컬 빌드와 테스트는 다음 명령으로 진행함
git clone https://github.com/quickwit-oss/tantivy.git
cd tantivy
cargo test
범위 밖 기능과 데이터 변경 모델
- 분산 검색은 Tantivy의 범위 밖임
- 분산 검색이 필요하면 Quickwit을 확인하라고 안내함
- Tantivy의 데이터는 immutable임
- 문서를 수정하려면 기존 문서를 삭제하고 다시 인덱싱해야 함
- 인덱싱 중인 문서는
IndexWriter에서commit이 호출된 뒤 검색 가능함 - 기존
IndexReader는 변경 사항을 반영하려면 재로드해야 함 - 변경 사항은 새로 획득한
Searcher에서만 보임
바인딩과 사용 사례
- 다른 언어에서 사용할 수 있는 바인딩
- Python: tantivy-py
- Ruby: tantiny
- GitHub에서 다른 바인딩도 찾을 수 있지만 유지보수가 덜 되어 있을 수 있음
- Tantivy 사용 예시
- Tantivy를 사용하는 회사로 Etsy, ParadeDB, Nuclia, Humanfirst.ai, Element.io가 표시됨
댓글과 토론
Hacker News 의견들
-
이 라이브러리 만든 분들 정말 대단함. 작년에 오래 방치했던 낡은 Python2 AppEngine 코드베이스를 대체하면서 https://progscrape.com [1]을 이 위에 다시 만들었는데, 훌륭한 라이브러리고 엄청 빠름
Raspberry Pi에서 100만 개 스토리 전체를 몇 초 만에 색인할 정도임
집의 Pi에서 전문 검색 서비스를 돌리고 있고, 피크 부하는 몇 rps 정도라 크진 않지만 CPU도 몇 퍼센트 이상 거의 튀지 않음. Pi에서 검색을 약 100rps까지 부하 테스트했는데 버텼음. 거의 그대로 끼워 넣을 수 있는 매우 유용한 라이브러리였고, 버그 리포트에도 팀이 매우 빠르게 대응했으며 버그도 아주 적었음
이렇게 작은 장치에서 검색 반응성이 어떤지 보려면 각 스토리의 라벨을 눌러보면 됨. 사실상 즉시 질의되고, 최대 10년 * 12개월치 검색 샤드를 치고 있음: https://progscrape.com/?search=javascript
현대적인 프로젝트라면 Lucene보다 이걸 살펴보길 추천함. 작은 ARM64에서도 이렇게 잘 확장되니, 더 큰 서버에서는 훨씬 더 좋은 경험을 할 가능성이 큼
[1] https://github.com/progscrape/progscrape- 정말 좋은 라이브러리임. JMAP을 쓰는 이메일 제공자를 대상으로, 아직 한창 작업 중인 증분 이메일 백업 CLI 도구에 사용 중임
사용자가 백업을 검색할 수 있게 하고 싶었고, Rust를 쓰고 있어서 Tantivy가 딱 맞아 보였음. 이메일 하나를 색인하는 속도가 너무 빨라서 별도 스레드로 옮길 필요도 없었고, 수천 개 이메일 검색도 문제 없어 보임
Rust 애플리케이션에 검색이 필요하다면 Tantivy를 살펴보면 좋음 - 작은 버그 리포트: https://progscrape.com/?search=grep에서
Error: PersistError(UnexpectedError("Storage fetch panicked"))가 표시됨 - 며칠 전 빠른 개념 증명용으로 meilisearch를 썼는데, 이 저장소를 통해 Tantivy를 다시 확인해봐야겠음
기본적으로 필요한 건 전문 검색뿐임
- 정말 좋은 라이브러리임. JMAP을 쓰는 이메일 제공자를 대상으로, 아직 한창 작업 중인 증분 이메일 백업 CLI 도구에 사용 중임
-
최근 ParadeDB 안에서 Tantivy를 발견했음. ParadeDB는 Elastic을 대체하려는 Postgres 확장임
https://github.com/paradedb/paradedb/blob/dev/pg_search/Carg...
“Extending Postgres for High Performance Analytics (with Philippe Noël)”를 듣고 알게 됨
https://www.youtube.com/watch?v=NbOAEJrsbaM
그리고 핵심 프로젝트인 Quickwit에도 들어감. 로그, 추적, 곧 메트릭까지 다루는 프로젝트임
https://github.com/quickwit-oss/quickwit
다국어 검색 개인 프로젝트에서 Quickwit과 ClickHouse를 함께 써봤는데 놀랄 만큼 좋았음. 드디어 중국어, 일본어, 한국어에 쓸 만한 조합이 나옴
https://quickwit.io/docs/guides/add-full-text-search-to-your...
PostgreSQL의to_tsvector는 내 사용 사례에서는 제대로 잘 맞은 적이 없었음
SELECT * FROM dump WHERE to_tsvector('english'::regconfig, hh_fullname) @@ to_tsquery('english'::regconfig, 'query');
잘되길 바람. Tantivy가 키워드로 들어간 글은 자동으로 추천 누를 듯함- URL/REST 기반 색인과 검색 질의를 전부 SQL 안에서 처리하는 조합이 멋진 설계 패턴임. Postgres FDW로도 같은 방식을 할 수 있음
-
최근 Tantivy 기반이고 같은 팀이 만든 Quickwit을 프로덕션에 배포해서 수십억 개 객체를 색인했는데 매우 만족스러움. 색인 속도가 훌륭하고 질의 지연시간도 경쟁력 있음
무엇보다 중요한 건 컴퓨트와 스토리지 분리가 엄청난 가치를 줬다는 점임. 장시간 돌아가는 고성능 서버 비용을 내지 않고도 객체 스토리지의 수십억 개 객체 위에 새 검색 서비스를 띄우고, 복잡한 집계까지 할 수 있어서 원래라면 꽤 비쌌을 새 사용 사례가 가능해졌음
사용 사례가 고성능 서버를 정당화할 정도가 되면, Quickwit은 각 서버에 데이터를 캐시해서 성능을 높이는 선택지도 제공함
큰 보너스로 Discord에서 팀이 매우 빠르고 친절하게 도와줌 -
또 다른 자료로는 etsy/hound[0]에서 쓰는 Go 기반 트라이그램 검색 색인이 있음. Russ Cox의 글과 코드인 “Regular Expression Matching with a Trigram Index”[1]에 기반함
[0] https://github.com/hound-search/hound
[1] http://swtch.com/~rsc/regexp/regexp4.html
필요에 따라 Lucene의 대안도 사용 사례가 달라짐 -
주의할 점은 아직도 필드 추가/삭제가 안 된다는 것임: https://github.com/quickwit-oss/tantivy/issues/470
필드를 추가하는 유일한 방법은 모든 데이터를 다른 검색 색인에 다시 색인하는 것임- 우회 방법으로 JSON 필드를 쓸 수 있음. 문서 참고: https://github.com/quickwit-oss/tantivy/blob/main/doc/src/js...
-
기본으로 원격 측정 데이터를 보내는 Meilisearch의 대안을 찾다가 Tantivy를 발견함. 검색 엔진 그 자체라기보다는 검색 엔진 빌더에 가깝지만, 설정은 꽤 단순해 보임 [0]
[0]: https://github.com/quickwit-oss/tantivy-cli- QuickWit도 기본으로 원격 측정을 보냄: https://quickwit.io/docs/telemetry
- 관심은 가지만 Rust 라이브러리로 쓰면서 JSON 설정 대신 Rust 타입만 다루고 싶음
Meilisearch의 Java SDK도 좋았음. CLI와 수동 설정이 필요 없고, 데이터베이스 엔티티를 가리키기만 하면 테이블 전체를 색인할 수 있었음
Tantivy에서도 그런 방식이 있으면 좋겠음 - 명령줄 인자 하나만 추가하면 쉽게 끌 수 있는데, 쓸 만한 대화형 검색을 두고 그걸 이유로 거부하는 건 사소한 반대처럼 보임
-
Tantivy는 LanceDb라는 흥미로운 벡터 데이터베이스 제품에서도 전문 검색 기능을 제공하는 데 쓰임: https://lancedb.github.io/lancedb/fts/
마지막으로 봤을 때는 Python 바인딩을 통해서만 가능했지만, 다른 플랫폼을 지원하기 위해 Rust 바인딩을 네이티브로 구현하려는 것으로 알고 있음 -
몇 년 전 Elasticsearch가 너무 자원 먹는 괴물이라 미친 듯이 답답해서 개인 프로젝트를 시작했음. 내 개인 컴퓨터조차 여러 넉넉한 스타트업이 제품에 할당하는 것보다 자원이 많은 편인데도 그랬음
Tantivy를 고른 이유는 두 가지였음. 하나는 전부 Rust로 만들고 싶었고, 다른 하나는 Tantivy 자체였음. 성능은 10/10이고, 문서는 최고 수준이며, 라이브러리 사용감도 매우 좋음
아쉽게도 혼자 여가 시간에 감당하기엔 프로젝트 범위가 너무 커서 포기했지만, 그래도 Tantivy는 정말 훌륭함 -
Tantivy를 한동안 지켜보고 있었음. 창업자들의 끈기와 최근 Tantivy가 달성한 성능이 인상적임
팀 전체에 큰 박수를 보냄. 이들이 목표를 이룰 거라고 굳게 믿음 -
Lucene과 Solr를 많이 써본 입장에서 가장 바라는 건 업그레이드 지원임. 보통 Lucene, Solr, ES 색인은 새 버전으로 업그레이드할 수 없음. 경우에 따라 가능하긴 하지만 편의상 제외하겠음
대형 프로젝트에서는 재색인이 매우 비싸고, 때로는 불가능에 가까운 작업임
절대 불가능할 가능성이 높은 경우도 있음. 예를 들어 손실이 있는 색인 필드에서 자료형의 색인 알고리즘이 바뀐 경우가 그렇다. 하지만 많은 경우에는 모든 정보가 남아 있으니, 그런 색인을 식별하고 업그레이드할 수 있으면 정말 좋겠음