π§ AI with Python β π Semantic Search Using FAISS
Posted on: October 22, 2026
Description:
Traditional search systems primarily rely on keyword matching to retrieve information. However, users often describe the same concept using different words, making it difficult for keyword-based systems to identify relevant results.
Semantic Search addresses this limitation by retrieving information based on meaning rather than exact word matches.
In this project, we'll explore how to build a semantic search engine using FAISS (Facebook AI Similarity Search) and Sentence Transformers, two important components of modern Retrieval-Augmented Generation (RAG) systems.
What is Semantic Search?
Semantic Search is an information retrieval technique that identifies relevant documents by comparing their semantic meaning with a user's query. For example, consider the question:
"How do computers understand human language?"
A semantic search system can identify a document discussing Natural Language Processing (NLP) even when it doesn't contain the exact words used in the question.
This is possible through Vector Embeddings, which represent text as numerical vectors. Documents with similar meanings generally have embeddings that are closer together in vector space. Unlike keyword matching, semantic search can recognise relationships between different expressions of the same concept.
How Does FAISS Enable Semantic Search?
FAISS is an open-source library developed by Meta for efficient similarity search over numerical vectors.
It allows developers to organise document embeddings into searchable indexes and retrieve vectors that are closest to a given query. For this project, we'll use IndexFlatIP, which performs exact nearest-neighbor searches using inner-product similarity.
When embeddings are normalised to unit length, inner-product similarity becomes equivalent to cosine similarity, a common metric for comparing semantic relationships. FAISS handles vector retrieval, while Sentence Transformers generates the embeddings needed for searching.
Building a Semantic Search Engine
We'll begin by converting our document collection into numerical embeddings using the pre-trained all-MiniLM-L6-v2 model.
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")
documents = [
"Machine Learning enables computers to learn patterns from data.",
"Natural Language Processing helps computers understand human language.",
"FAISS enables efficient similarity search across vector embeddings."
]
embeddings = model.encode(documents, convert_to_numpy=True)
The model generates 384-dimensional embeddings for each document, capturing aspects of their semantic meaning.
Next, we'll normalise these embeddings and store them in a FAISS index.
import faiss
import numpy as np
embeddings = np.asarray(embeddings, dtype="float32")
faiss.normalize_L2(embeddings)
index = faiss.IndexFlatIP(embeddings.shape[1])
index.add(embeddings)
Our document collection is now indexed and ready for similarity searches.
Retrieving Relevant Documents
When a user submits a query, the system converts it into an embedding using the same model and compares it against the indexed documents.
query = "How do computers understand human language?"
query_vector = model.encode([query], convert_to_numpy=True)
query_vector = np.asarray(query_vector, dtype="float32")
faiss.normalize_L2(query_vector)
scores, indices = index.search(query_vector, 2)
for i, score in zip(indices[0], scores[0]):
print(documents[i], score)
FAISS returns the two most similar documents along with their similarity scores. In this example, the document about Natural Language Processing should rank highly because it closely matches the query's meaning. However, similarity scores measure relationships between embeddings and do not guarantee factual correctness.
Semantic Search in RAG Systems
Semantic search plays an important role in Retrieval-Augmented Generation by identifying relevant information before an LLM generates its response.
A typical RAG workflow follows this sequence:
Documents β Embeddings β FAISS Index β Semantic Search β Retrieved Context β LLM Response
When a user asks a question, the system retrieves relevant document chunks and provides them to an LLM as additional context. This approach allows AI applications to answer questions using external information instead of relying entirely on the model's existing knowledge. FAISS performs the retrieval process; the language model handles response generation.
Real-World Applications
Semantic search using FAISS can support several practical applications, including document question-answering systems, enterprise knowledge assistants, customer support applications, and recommendation engines.
For example, an internal knowledge assistant can retrieve relevant technical documentation based on an employee's question, even when the wording differs from the original document.
Similarly, RAG applications can use semantic search to retrieve useful context from PDFs, knowledge bases, and other document collections.
Final Thoughts
Semantic Search Using FAISS demonstrates how vector embeddings and similarity search work together to retrieve information based on meaning.
In this project, we explored how to generate document embeddings using Sentence Transformers, build a FAISS index, and retrieve relevant documents through cosine similarity.
These concepts form an important foundation for developing intelligent search engines and retrieval-based AI applications.
Code Snippet:
import faiss
import numpy as np
from sentence_transformers import SentenceTransformer
# =========================================================
# Step 1 - Create Document Collection
# =========================================================
documents = [
"Python is widely used for automation, web development, and data science.",
"Machine Learning enables computers to learn patterns from data.",
"Deep Learning uses neural networks with multiple layers.",
"Natural Language Processing helps computers understand human language.",
"FAISS enables efficient similarity search across vector embeddings.",
"Retrieval-Augmented Generation retrieves external information to support LLM responses.",
"Vector embeddings represent the semantic meaning of text as numerical vectors.",
"Semantic search retrieves relevant information based on meaning rather than keywords."
]
print("=" * 60)
print("Document Collection")
print("=" * 60)
for i, document in enumerate(documents, start=1):
print(f"{i}. {document}")
# =========================================================
# Step 2 - Load Embedding Model
# =========================================================
print("\nLoading Sentence Transformer Model...")
model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")
print("Embedding model loaded successfully!")
# =========================================================
# Step 3 - Generate Document Embeddings
# =========================================================
embeddings = model.encode(documents, convert_to_numpy=True)
embeddings = np.asarray(embeddings, dtype="float32")
print("\n" + "=" * 60)
print("Document Embeddings")
print("=" * 60)
print(f"Embedding Shape: {embeddings.shape}")
print(f"Embedding Dimensions: {embeddings.shape[1]}")
# =========================================================
# Step 4 - Normalize Embeddings
# =========================================================
# Normalization allows inner product to represent cosine similarity
faiss.normalize_L2(embeddings)
print("\nDocument embeddings normalized successfully!")
# =========================================================
# Step 5 - Build FAISS Vector Index
# =========================================================
dimension = embeddings.shape[1]
index = faiss.IndexFlatIP(dimension)
index.add(embeddings)
print("\n" + "=" * 60)
print("FAISS Vector Index")
print("=" * 60)
print(f"Index Type: IndexFlatIP")
print(f"Indexed Documents: {index.ntotal}")
print(f"Vector Dimensions: {index.d}")
# =========================================================
# Step 6 - Create Semantic Search Function
# =========================================================
def semantic_search(query, top_k=3):
if top_k < 1:
raise ValueError("top_k must be greater than zero.")
# Convert query into an embedding
query_embedding = model.encode([query], convert_to_numpy=True)
query_embedding = np.asarray(query_embedding, dtype="float32")
# Normalize query embedding for cosine similarity
faiss.normalize_L2(query_embedding)
# Retrieve the most similar document embeddings
scores, indices = index.search(query_embedding, min(top_k, index.ntotal))
results = []
for doc_index, score in zip(indices[0], scores[0]):
results.append({
"document": documents[doc_index],
"similarity": float(score)
})
return results
# =========================================================
# Step 7 - Perform Semantic Search
# =========================================================
query = "How do computers understand human language?"
results = semantic_search(query, top_k=3)
print("\n" + "=" * 60)
print("Semantic Search Results")
print("=" * 60)
print(f"Query: {query}")
for rank, result in enumerate(results, start=1):
print(f"\nRank {rank}")
print(f"Document: {result['document']}")
print(f"Similarity Score: {result['similarity']:.4f}")
# =========================================================
# Step 8 - Test Multiple Search Queries
# =========================================================
queries = [
"How does AI learn from data?",
"What is semantic search?",
"How can language models access external information?"
]
print("\n" + "=" * 60)
print("Testing Multiple Search Queries")
print("=" * 60)
for search_query in queries:
print(f"\nQuery: {search_query}")
results = semantic_search(search_query, top_k=2)
for rank, result in enumerate(results, start=1):
print(f"{rank}. {result['document']}")
print(f" Similarity: {result['similarity']:.4f}")
# =========================================================
# Step 9 - Display Final Summary
# =========================================================
print("\n" + "=" * 60)
print("Semantic Search Summary")
print("=" * 60)
print("Embedding Model: all-MiniLM-L6-v2")
print(f"Total Documents: {len(documents)}")
print(f"Embedding Dimensions: {dimension}")
print("FAISS Index: IndexFlatIP")
print("Similarity Metric: Cosine Similarity")
print("Application: Semantic Search and RAG Systems")
# =========================================================
# Program Completed
# =========================================================
print("\n" + "=" * 60)
print("Semantic Search Using FAISS Demo Completed Successfully!")
print("=" * 60)
No comments yet. Be the first to comment!