---
title: "How do I do semantic search in Python?"
description: "Semantic search in Python: embed passages, declare an index on the table, and rank with similarity(string=). A separate vector database is optional."
url: "https://www.pixeltable.com/learn/how-to/semantic-search-in-python"
updated: "2026-10-14"
doc: "https://docs.pixeltable.com/howto/cookbooks/search/search-semantic-text"
---

# 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: 2026-10-14
Part of [How do I ... in Python?](https://www.pixeltable.com/learn/how-to).

## 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

## On this page

- [Before you start](https://www.pixeltable.com/learn/how-to/semantic-search-in-python#before-you-start)
- [Store the passages you will search](https://www.pixeltable.com/learn/how-to/semantic-search-in-python#step-1)
- [Declare the embedding index on that column](https://www.pixeltable.com/learn/how-to/semantic-search-in-python#step-2)
- [Rank by similarity to a sentence](https://www.pixeltable.com/learn/how-to/semantic-search-in-python#step-3)
- [Comparison](https://www.pixeltable.com/learn/how-to/semantic-search-in-python#comparison)
- [Where Pixeltable fits](https://www.pixeltable.com/learn/how-to/semantic-search-in-python#where-pixeltable-fits)
- [Questions](https://www.pixeltable.com/learn/how-to/semantic-search-in-python#questions)

## 1. Store the passages you will search {#step-1}

Semantic search needs the text on a row, plus any metadata you will filter on. A vector with no source string cannot cite anything.

```python
import pixeltable as pxt
from pixeltable.functions.huggingface import sentence_transformer

TableModel = pxt.model_base()
text_embed = sentence_transformer.using(model_id='all-MiniLM-L6-v2')

class Notes(TableModel, name='notes'):
    title: pxt.String
    content: pxt.String
    category: pxt.String
```

## 2. Declare the embedding index on that column {#step-2}

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.

```python
class Notes(TableModel, name='notes'):
    title: pxt.String
    content: pxt.String
    category: pxt.String
    __indexes__ = [
        pxt.EmbeddingIndex(content, string_embed=text_embed),
    ]
```

## 3. Rank by similarity to a sentence {#step-3}

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.

```python
@pxt.query
def 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 {#comparison}

|  | 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 {#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.

```python
import pixeltable as pxt
from pixeltable.functions.huggingface import sentence_transformer

TableModel = 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.query
def 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)
```

## Concepts

- [What is semantic search?](https://www.pixeltable.com/learn/what-is-semantic-search)
- [How does an embedding index differ from a vector database?](https://www.pixeltable.com/learn/embedding-index-vs-vector-database)
- [Vector database alternatives for multimodal apps](https://www.pixeltable.com/learn/vector-database-alternatives-for-multimodal-apps)

## Use case

- [Multimodal AI Apps: Process Any Data Type in One System](https://www.pixeltable.com/use-cases/multimodal-ai-application-development)

## Questions {#questions}

### Is semantic search the same as a vector database? {#faq-1}

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? {#faq-2}

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? {#faq-3}

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.

## Related

- [What is semantic search?](https://www.pixeltable.com/learn/what-is-semantic-search)
- [Embedding index vs a vector database](https://www.pixeltable.com/learn/embedding-index-vs-vector-database)
- [Vector database alternatives for multimodal apps](https://www.pixeltable.com/learn/vector-database-alternatives-for-multimodal-apps)
- [Multimodal application development](https://www.pixeltable.com/use-cases/multimodal-ai-application-development)
- [How do I do hybrid search in Python?](https://www.pixeltable.com/learn/how-to/hybrid-search-in-python)
- [Pixeltable vs Pinecone](https://www.pixeltable.com/compare/pixeltable-vs-pinecone)
- [Pixeltable vs Weaviate](https://www.pixeltable.com/compare/pixeltable-vs-weaviate)
- [Pixeltable vs LanceDB](https://www.pixeltable.com/compare/pixeltable-vs-lancedb)
- [Build semantic search for text](https://docs.pixeltable.com/howto/cookbooks/search/search-semantic-text)
