Build a Full Text Search Index in Python

Create a simple inverted index for full-text search with the standard library, supporting multi-word AND queries across documents.

Medium Python 3.9+ Aug 9, 2026 Database scaling & optimization 12 views 0 copies

Python code

36 lines
Python 3.9+
import re
from collections import defaultdict


class SimpleTextIndex:
    def __init__(self):
        self.index = defaultdict(list)
        self.documents = {}

    def add_document(self, doc_id, text):
        self.documents[doc_id] = text
        words = set(re.findall(r'\w+', text.lower()))
        for word in words:
            self.index[word].append(doc_id)

    def search(self, query):
        query_words = re.findall(r'\w+', query.lower())
        if not query_words:
            return []
        result = set(self.index.get(query_words[0], []))
        for word in query_words[1:]:
            result.intersection_update(self.index.get(word, []))
        return sorted(result)


if __name__ == "__main__":
    idx = SimpleTextIndex()
    idx.add_document(1, "The quick brown fox jumps over the lazy dog")
    idx.add_document(2, "Python is a great language for data science")
    idx.add_document(3, "The lazy cat sleeps all day")
    idx.add_document(4, "Data analysis with python and pandas")

    print("Search 'lazy':", idx.search("lazy"))
    print("Search 'python data':", idx.search("python data"))
    print("Search 'quick fox':", idx.search("quick fox"))
    print("Search 'nonexistent':", idx.search("nonexistent"))

Output

stdout
Search 'lazy': [1, 3]
Search 'python data': [2, 4]
Search 'quick fox': [1]
Search 'nonexistent': []

How it works

The SimpleTextIndex builds an inverted index where each word maps to a list of document IDs containing it. add_document tokenizes text into unique words using regex and stores them in a defaultdict(list). The search method converts the query into words, starts with the document set for the first term, and uses intersection_update to AND-filter with subsequent terms, returning sorted results. This gives O(1) lookup per word followed by set intersection, which scales well for medium-sized collections.

Common mistakes

  • Forgetting to handle lowercase normalization leading to case-sensitive mismatches
  • Using a list instead of a set for intermediate results causing duplicate IDs in output
  • Not deduplicating words per document before indexing, inflating the index size

Variations

  1. Add relevance ranking with TF-IDF scores instead of plain set intersections
  2. Use `re.findall(r'[a-z0-9]+')` to restrict tokens to alphanumeric sequences only

Real-world use cases

  • In-memory search over a product catalog or documentation corpus in a small service.
  • Building a lightweight autocomplete or tag filter backend where a full engine is overkill.
  • Prototyping search features before migrating to Elasticsearch or a database FTS column.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Database scaling & optimization

Related tutorials and quizzes for this topic.