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.
Python code
36 linesimport 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
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
- Add relevance ranking with TF-IDF scores instead of plain set intersections
- 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
More from Database scaling & optimization
- Approximate Count with HyperLogLog in Python medium
- B-Tree Insert and In-Order Traversal in Python hard
- Broadcast a Small Reference Table in Python easy
- Build a Partial Index Mock in Python for Database Filtering easy
- Composite index leftmost prefix in Python medium
- Consistent Hashing with Virtual Buckets in Python medium
Keep learning
Related tutorials and quizzes for this topic.