Pinecone for Vector Search
Theme
Palette
Download
Caption (tap to copy)
📖 Deep dive (full written explanation)
Post 4 is the hands-on tour and the cover sets the expectation: this is the post you keep open as a cheat sheet. Every slide is a runnable Python snippet against a live Pinecone project, building from creating an index through embedding, upserting, querying, filtering, and namespacing.
The pedagogical idea is that you learn a vector database by doing, not by reading definitions. Posts 1 through 3 gave you the model and the mechanics; this post puts your hands on the controls. By the end you'll have seen the full lifecycle — text becomes vectors, vectors go into the index, and queries come back ranked and filtered.
Initialization and index creation are the natural starting point because nothing else works without them. The Pinecone client is constructed with your API key. The guard around create_index — checking list_indexes first — matters because creating an index that already exists raises an error, and you don't want a re-run of your setup script to crash.
The creation call fixes the two permanent properties from post 3: dimension must equal your embedding model's output size (1536 for text-embedding-3-small), and metric is the similarity measure (cosine). ServerlessSpec selects a cloud and region and means you don't pre-provision capacity. After creation, pc.Index('docs') returns a handle you'll use for every upsert and query. Get the dimension and metric right here, because they cannot be changed afterward — you'd have to delete and rebuild.
Embedding is the step Pinecone doesn't do for you, so this slide shows it explicitly. The embed helper wraps a single embedding model and returns plain lists of floats. Two design choices are worth copying. First, it accepts a list of texts and embeds them in one API call, which is far more efficient than calling the model once per string. Second, it centralizes the model name in one place.
That centralization is not incidental — it's the defense against the single most common Pinecone mistake, covered in post 5. If both your indexing code and your query code call this same embed function, they can never accidentally use different models, which would silently misalign the vector spaces. Note the comment pinning the dimension to 1536 to match the index; the model's output size and the index's dimension are two halves of the same contract.
Upsert is how vectors get into the index, and 'upsert' is precise: it inserts a vector if its id is new and overwrites it if the id already exists. Each record has three parts you've seen before — an id, the values array (the embedding), and a metadata object. Here the metadata records a topic and page, the fields you'll filter on shortly.
The trailing comment is real-world advice, not decoration: upserting in batches of around 100 vectors dramatically improves throughput compared to one call per vector, because it amortizes network round trips. For a large corpus this is the difference between an import that finishes in minutes and one that drags for hours. The idempotent nature of upsert also means you can safely re-run an import after a failure without creating duplicates, as long as your ids are stable.
This is the payoff slide: a semantic query and reading its results. The query text is embedded with the same helper (note 'how do I change my login?' shares no words with the stored 'Reset your password from Settings.'), top_k=3 asks for the three closest matches, and include_metadata=True brings back the stored context.
The loop over res['matches'] shows what you get: each match has an id, a score, and its metadata. The score is the similarity under the index's metric — with cosine, higher means more similar, and it's how you'd decide whether a match is good enough to use or set a relevance threshold. The fact that the login question retrieves the password-reset document despite zero shared keywords is the entire promise of vector search, demonstrated in a few lines. This is the moment the abstractions from posts 1 to 3 become tangible.
Filtering is what makes the query production-ready, and this slide layers it onto the previous query. The same query vector and top_k are used, but now a filter restricts results to vectors whose metadata has topic equal to 'billing' and page at or above 5. Pinecone evaluates the filter during the search, so you get semantically relevant results that also satisfy the structured constraints — in one round trip, not by post-filtering in Python.
The operator syntax ($eq, $gte) mirrors MongoDB-style queries, which keeps the learning curve gentle. The practical power here is scoping: in a multi-tenant app you'd filter by tenant; in a time-sensitive one you'd filter by date; for permissions you'd filter by visibility. This single capability — combining 'means similar' with 'and satisfies these rules' — is what separates a toy semantic search from one you can safely ship.
The pipeline diagram zooms out from individual calls to the whole lifecycle, which is the mental model to retain: text (both your documents and the incoming query) is embedded into vectors, document vectors are upserted into the index, and queries retrieve the top matches with optional filters. It's the same loop the RAG diagram in post 2 hinted at, now shown as the concrete operations you just wrote.
Seeing it end to end reinforces that embedding sits on both ends — you embed once to store and again to query, and crucially with the same model both times. The diagram is a good thing to picture when designing your own pipeline: it tells you the four moving parts you must build and the order they run in.
Namespaces are the multi-tenancy and partitioning tool, and this slide shows how little code they take. Adding namespace='acme' to an upsert files those vectors into a separate partition within the same index, and a query with namespace='acme' searches only that partition. Vectors in different namespaces never mix in results.
This is the clean way to isolate customers' data in a SaaS product: one namespace per tenant means a query can't accidentally surface another tenant's documents, and you can delete a whole tenant's data by clearing their namespace. Namespaces are cheaper and simpler than running a separate index per tenant, while still giving hard isolation at query time. They also serve non-tenant uses — separating environments, or splitting a corpus by language or document type.
Updates and deletes complete the lifecycle, and this slide shows the everyday maintenance operations. index.update with set_metadata changes a vector's metadata without re-embedding it — useful when only the tags or status changed, not the underlying text. index.delete by ids removes specific vectors, and delete with delete_all scoped to a namespace wipes that entire partition in one call.
These operations are what keep an index fresh and correct over time, and forgetting them is a cost-and-staleness mistake covered in post 5. When a source document is removed, you delete its vector; when it changes materially, you re-embed and upsert it (the upsert overwrites by id). The namespace-wide delete is the clean offboarding path for a departing tenant. Building these into your data pipeline from the start prevents the index from drifting out of sync with your real data.
The cheat-sheet recap is the post's deliverable — five lines that cover the full Pinecone working loop. Create the index once with the right dimension and metric; embed text with a fixed model; upsert ids, values, and metadata in batches; query with a vector, top_k, optional filter, and optional namespace; and maintain the data with metadata updates and deletes.
The value of compressing it this tightly is recall under pressure. When you're actually building, these five operations are the entire surface area you touch most of the time. Knowing them cold lets you move fast, and the order they're listed in mirrors the natural lifecycle of data flowing through a vector search system.
This cta closes the code tour and sets up the final post. You've now created, embedded, upserted, queried, filtered, namespaced, updated, and deleted — you can drive Pinecone end to end. The natural next step is learning the ways people drive it into a wall.
The teaser frames post 5 around mistakes: the relevance and budget failures that don't show up in a tutorial but absolutely show up in production. Knowing the happy path is half the job; knowing the failure modes is what makes you trustworthy with a real vector search system.