How to
How do I do semantic search in Python?
Semantic search in Python ranks rows by meaning: embed the query and the stored text with the same model, then return nearest neighbors. A vector database in Python is one way to store those vectors. The other is an index on the table that already holds the passages, so insert updates search without a second copy.
Updated · Part of How do I ... in Python?
Before you start
About 15 min.
- Python 3.11+
- pip install -U 'pixeltable[serve]'
- pxt init in the project root
- sentence-transformers for all-MiniLM-L6-v2
1. Store the passages you will search
Semantic search needs the text on a row, plus any metadata you will filter on. A vector with no source string cannot cite anything.
import pixeltable as pxtfrom pixeltable.functions.huggingface import sentence_transformerTableModel = pxt.model_base()text_embed = sentence_transformer.using(model_id='all-MiniLM-L6-v2')class Notes(TableModel, name='notes'):title: pxt.Stringcontent: pxt.Stringcategory: pxt.String
2. Declare the embedding index on that column
A vector database in Python is often a second product you upsert into. An embedding index on the column is the same nearest-neighbor search without the copy. Insert a row and the vector follows.
class Notes(TableModel, name='notes'):title: pxt.Stringcontent: pxt.Stringcategory: pxt.String__indexes__ = [pxt.EmbeddingIndex(content, string_embed=text_embed),]
3. Rank by similarity to a sentence
Embed the question with the same model. order_by the similarity score descending. Limit is the number of neighbors. Keyword search is a different index; combine it only if exact tokens matter.
@pxt.querydef search_notes(query: str, limit: int = 5):sim = Notes.content.similarity(string=query)return (Notes.order_by(sim, asc=False).limit(limit).select(Notes.title, Notes.content, sim))
Semantic search versus a vector database
| Index on the table | A vector database in Python | |
|---|---|---|
| Stores | The passage and the vector | The vector, plus metadata you copy in |
| Insert | The index updates with the row | An upsert you remember to run |
| Query | column.similarity(string=) | A client against another service |
| When to split | Rare: another system is already source of truth | Hosted ANN, namespaces, or a query SLA |
Where Pixeltable fits
Pixeltable is the unified multimodal backend: EmbeddingIndex on the column that holds the text, then similarity(string=). A vector database in Python is optional. Keep Pinecone or Weaviate when that engine is the serving contract; see the vector database alternatives roundup.
import pixeltable as pxtfrom pixeltable.functions.huggingface import sentence_transformerTableModel = pxt.model_base()text_embed = sentence_transformer.using(model_id='all-MiniLM-L6-v2')class Notes(TableModel, name='notes'):content: pxt.String__indexes__ = [pxt.EmbeddingIndex(content, string_embed=text_embed),]@pxt.querydef search_notes(query: str, limit: int = 5):sim = Notes.content.similarity(string=query)return Notes.order_by(sim, asc=False).limit(limit).select(Notes.content, sim)
Questions
- Is semantic search the same as a vector database?
- Semantic search is the ranking. A vector database is one place to store the vectors. The index can also live on the table that holds the passages. You need the ranking; you need a separate database only when that engine is the product.
- How is this different from keyword search?
- Keyword search matches tokens. Semantic search matches meaning, so a paraphrase can still hit. Exact product names or error codes often want a keyword filter beside the embedding.
- Which embedding model should I use?
- all-MiniLM-L6-v2 is the documented fast local default. all-mpnet-base-v2 is stronger and slower. Hosted models such as OpenAI text-embedding-3-small are an API. Use the same model at insert and at query.