Semantic search surpasses simple keyword matching because embeddings place texts in a highâdimensional vector space where cosine similarity directly reflects intent. A dedicated vector store is therefore required to persist those embeddings and serve nearestâneighbor queries efficiently. This post demonstrates a pinecone fastapi semantic search tutorial that wires a FastAPI service to Pinecone, showing the full data flow from embedding generation to similarity lookup.
đ Table of Contents
Creating a reproducible environment guarantees that the tutorial runs identically on any machine.
$ python3 -m venv venv
$ source venv/bin/activate
(venv) $ python -V
Python 3.11.5
Activating the virtual environment isolates package installations from the global interpreter.
$ pip install fastapi[all] uvicorn pinecone-client sentence-transformers
Collecting fastapi[all] Down fastapi-0.109.0-py3-none-any.whl (48 kB)
Collecting uvicorn Down uvicorn-0.24.0-py3-none-any.whl (66 kB)
Collecting pinecone-client Down pinecone_client-2.2.2-py3-none-any.whl (81 kB)
Collecting sentence-transformers Down sentence_transformers-2.2.2-py3-none-any.whl (1.1 MB)
...
Successfully installed fastapi-0.109.0 uvicorn-0.24.0 pinecone-client-2.2.2 sentence-transformers-2.2.2
(venv) $ pip list | grep -E 'fastapi|uvicorn|pinecone|sentence-transformers'
fastapi 0.109.0
uvicorn 0.24.0
pinecone-client 2.2.2
sentence-transformers 2.2.2
All packages are pulled from PyPI, which mirrors the official releases of each library.
Key point: A clean virtual environment guarantees deterministic builds, a prerequisite for reliable semantic search services.
The service provides three endpoints: a health check, a document ingestion route, and a search route that returns the most similar texts.
from pydantic import BaseModel class Document(BaseModel): id: str text: str class Query(BaseModel): query: str top_k: int = 5
FastAPI validates JSON payloads against these Pydantic models and automatically generates the corresponding OpenAPI schema.
from fastapi import FastAPI, HTTPException
from sentence_transformers import SentenceTransformer
import pinecone app = FastAPI(title="Semantic Search Service")
model = SentenceTransformer('all-MiniLM-L6-v2')
pinecone.init(api_key="YOUR_PINECONE_API_KEY", environment="us-west1-gcp")
index = pinecone.Index("semantic-demo") @app.get("/health")
def health(): return {"status": "ok"} @app.post("/ingest")
def ingest(doc: Document): vector = model.encode(doc.text).tolist() upsert_response = index.upsert(vectors=[(doc.id, vector, {"text": doc.text})]) if upsert_response['upserted_count']!= 1: raise HTTPException(status_code=500, detail="Failed to upsert") return {"result": "ingested"} @app.post("/search")
def search(q: Query): query_vec = model.encode(q.query).tolist() result = index.query(vector=query_vec, top_k=q.top_k, include_metadata=True) return {"matches": result["matches"]}
The chosen model, all-MiniLM-L6-v2
, yields 384âdimensional embeddings. Encoding a 1 KB passage typically completes in ~5 ms on a single CPU core, keeping request latency low. (Also read: đ§ Building a semantic search with Pinecone and FastAPI â the right way)
Key point: The FastAPI endpoints delegate all heavy lifting to the SentenceTransformer model and Pinecone's index, preserving a lightweight request path.
This section shows index creation, upserting documents, and performing a similarity search.
$ pinecone index list
+-------------------+-----------+----------+-------------------+
| Index Name | Dimension | Metric | Status |
+-------------------+-----------+----------+-------------------+
| semantic-demo | 384 | cosine | ready |
+-------------------+-----------+----------+-------------------+
According to the Pinecone documentation, an index is a collection of partitions that each hold a subset of vectors. The "cosine" metric triggers an approximate nearestâneighbor algorithm that normalizes vectors before innerâproduct calculation, which is ideal for semantic similarity. (More on PythonTPoint tutorials)
$ curl -X POST http://127.0.0.1:8000/ingest -H "Content-Type: application/json" -d '{"id":"doc1","text":"Machine learning enables computers to learn from data"}'
{"result":"ingested"}
The upsert call stores the embedding together with the original text as metadata. Pinecone places the vector in a partition based on a hash of the ID, guaranteeing O(1) write latency.
$ curl -X POST http://127.0.0.1:8000/search -H "Content-Type: application/json" -d '{"query":"What is deep learning?","top_k":3}'
{ "matches": [ { "id": "doc42", "score": 0.962, "metadata": {"text":"Deep learning is a subset of machine learning using neural networks"} }, { "id": "doc7", "score": 0.945, "metadata": {"text":"Neural networks can approximate complex functions"} }, { "id": "doc19", "score": 0.931, "metadata": {"text":"Supervised learning requires labeled data"} } ]
}
The response contains the topâk most similar vectors, ordered by cosine similarity score. Pinecone's internal ANN algorithm reduces the search complexity from O(N) to subâlinear time, typically O(log N) per query.
Key point: By delegating vector storage and ANN search to Pinecone, the FastAPI service stays stateless and horizontally scalable.
Understanding Pinecone's indexing strategy helps you tune the service for cost and speed. (Also read: âïž Exposing FastAPI with NGINX Ingress on Kubernetes â a key tutorial)
| Feature | Pinecone (Managed) | FAISS (Selfâhosted) |
|---|---|---|
| Provisioning | Oneâclick index creation, no hardware management | Manual GPU/CPU provisioning required |
| Scalability | Automatic sharding across clusters | Limited by single node resources |
| Latency (Typical 10 k vectors) | â 12 ms query | â 40 ms query (CPU) |
| Operational Overhead | Managed backups, monitoring, SLA | Custom scripts for persistence |
Pinecone stores vectors on SSDâbacked nodes and combines product quantization with inverted file structures. The query path first retrieves candidate partitions (logarithmic lookup) and then reâranks a small subset, which explains the ~12 ms latency observed for 10 k vectors. In contrast, a selfâhosted FAISS index on a single CPU must scan more candidates, leading to higher latency.
Key point: For workloads exceeding a few hundred thousand vectors, a managed service like Pinecone delivers predictable latency without custom scaling logic.
The pinecone fastapi semantic search tutorial shows that a concise FastAPI wrapper can expose powerful vector search capabilities with only a few lines of code. Off embedding storage and ANN retrieval to Pinecone eliminates the operational complexity of selfâhosting a similarity engine while preserving lowâlatency, scalable queries.
Adopting this pattern lets you concentrate on domainâspecific logicâsuch as document preprocessing or relevance feedbackârather than the mechanics of vector indexing. The result is a clean, maintainable code base that scales with data volume and query traffic.
Store the key in an environment variable or a secret manager (e.g., AWS Secrets Manager) and read it at runtime; never hardâcode it in source files.
Yes. Replace the SentenceTransformer('all-MiniLM-L6-v2')
initialization with any model that produces vectors matching the index dimension you created.
Pinecone indexes are immutable with respect to dimension; you must create a new index with the desired dimension and reâupsert all vectors.