Python Search Engine
O Python Search Engine é um motor de busca handmade em Python, construído do zero com armazenamento local e interface de linha de comando. Implementa um índice invertido binário serializado com pickle e o algoritmo de ranqueamento BM25 para indexar e recuperar documentos de texto (.txt) — sem dependências de motores externos (Lucene, Elasticsearch, etc).
The Python Search Engine is a handmade search engine in Python, built from scratch with local storage and a command-line interface. It implements a binary inverted index serialized with pickle and the BM25 ranking algorithm to index and retrieve text documents (.txt) — with no external engine dependencies (Lucene, Elasticsearch, etc).
Escopo da Fase 1Phase 1 scope
- CLI apenas (
search_cli.py).CLI only (search_cli.py). - Documentos
.txtapenas.Plain.txtdocuments only. - Armazenamento local persistente em
.search_data/.Local persistent storage in.search_data/. - Índice invertido binário (
pickle) + document store.Binary inverted index (pickle) + document store. - Ranqueamento via BM25.BM25 ranking.
Layout do armazenamentoStorage layout
.search_data/
docs/
<doc_id>.txt
index/
inverted_index.pkl
meta.json
Cada documento adicionado recebe um doc_id sequencial e é copiado para docs/. O índice invertido (inverted_index.pkl) mapeia termos → postings e fica serializado em binário; metadados (estatísticas de coleção, comprimento médio de documento, etc) ficam em meta.json.
Each document gets a sequential doc_id and is copied into docs/. The inverted index (inverted_index.pkl) maps terms → postings and is serialized in binary; collection metadata (statistics, average document length, etc) lives in meta.json.
Comandos da CLICLI commands
| ComandoCommand | FunçãoFunction |
|---|---|
init | Inicializa o armazenamento (.search_data/).Initializes the storage (.search_data/). |
add --file <path> | Adiciona um documento a partir de um arquivo.Adds a document from a file. |
add --text "..." | Adiciona texto bruto diretamente.Adds raw text directly. |
add --dir <path> | Adiciona, recursivamente, todos os .txt de um diretório.Recursively adds all .txt files in a directory. |
search --query "..." --top-k N | Busca a query e retorna os N documentos mais relevantes (BM25).Searches the query and returns the top-N most relevant documents (BM25). |
list | Lista todos os documentos indexados.Lists all indexed documents. |
stats | Mostra estatísticas da coleção.Shows collection statistics. |
remove --doc-id N | Remove um documento pelo doc_id.Removes a document by doc_id. |
--data-dir <path> | Opcional. Usa um diretório de dados customizado em qualquer subcomando.Optional. Uses a custom data directory on any subcommand. |
Instalação e usoInstall and usage
1. Clonar o repositório1. Clone the repository
$ git clone https://github.com/guilhermefelipetto/python-search-engine.git $ cd python-search-engine
2. Inicializar o armazenamento2. Initialize the storage
$ python search_cli.py init
3. Criar uma pasta de testes local3. Create a local test folder
$ mkdir local_docs
local_docs/está no.gitignore, então pode jogar qualquer documento de teste ali sem risco de comitar.local_docs/is in.gitignore, so you can drop any test document there without risk of committing it.
4. Adicionar documentos4. Add documents
# A partir de um arquivoFrom a file $ python search_cli.py add --file ./local_docs/my_doc.txt # Texto bruto direto na CLIRaw text inline $ python search_cli.py add --text "python bm25 inverted index" # Diretório inteiro (recursivo)Entire directory (recursive) $ python search_cli.py add --dir ./local_docs
5. Buscar5. Search
$ python search_cli.py search --query "python search" --top-k 5
Se nenhum documento estiver indexado, a CLI emite um aviso e encerra. If no document is indexed, the CLI prints a warning and exits.
6. Outras operações6. Other operations
$ python search_cli.py list # lista documentoslist documents $ python search_cli.py stats # estatísticas da coleçãocollection stats $ python search_cli.py remove --doc-id 3 # remove um documentoremove a document
Diretório de dados customizado (opcional)Custom data directory (optional)
$ python search_cli.py --data-dir ./my_local_engine init
Como funciona internamenteHow it works internally
Quando um documento é adicionado, o texto é tokenizado, stopwords são removidas e cada termo é registrado no índice invertido (estrutura que mapeia termo → lista de (doc_id, frequência, ...)). A estrutura é serializada em binário com pickle, o que torna a leitura e escrita extremamente rápidas em comparação a formatos textuais como JSON.
When a document is added, the text is tokenized, stopwords are removed, and each term is registered in the inverted index (a structure that maps term → list of (doc_id, frequency, ...)). The structure is serialized in binary with pickle, which makes reads and writes far faster than text-based formats like JSON.
Durante a busca, o algoritmo BM25 calcula um score de relevância para cada documento que contém termos da query, ponderando: (i) a frequência do termo no documento (TF saturada), (ii) a raridade do termo na coleção (IDF) e (iii) o comprimento do documento relativo à média (normalização). Os top-k documentos com maior score são retornados.
During search, the BM25 algorithm computes a relevance score for each document containing query terms, weighting: (i) term frequency in the document (saturated TF), (ii) term rarity across the collection (IDF), and (iii) document length relative to the collection average (length normalization). The top-k documents with highest scores are returned.
MotivaçãoMotivation
Este projeto foi desenvolvido para estudar, na prática, os fundamentos de Recuperação de Informação. Construir um motor de busca do zero é a forma mais direta de internalizar como funcionam a tokenização, a construção do índice invertido e a matemática por trás de algoritmos clássicos de ranqueamento como o BM25 — coisas que normalmente ficam escondidas atrás da API de motores prontos. A escolha por pickle ao invés de JSON foi deliberada: o objetivo era também experimentar serialização binária e o trade-off de velocidade × portabilidade.
This project was built to study the fundamentals of Information Retrieval hands-on. Building a search engine from scratch is the most direct way to internalize how tokenization, inverted index construction, and the math behind classic ranking algorithms like BM25 actually work — things normally hidden behind a high-level search engine API. The choice of pickle over JSON was deliberate: part of the goal was experimenting with binary serialization and its speed × portability trade-off.