Skip to content

Commit 2908ec8

Browse files
committed
Simplify README
1 parent 2814c8a commit 2908ec8

1 file changed

Lines changed: 5 additions & 265 deletions

File tree

README.md

Lines changed: 5 additions & 265 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,11 @@
2828
[![Slack URL](https://img.shields.io/badge/Join%20Slack-purple?logo=slack&link=https%3A%2F%2Fparadedb.com%2Fslack)](https://paradedb.com/slack)
2929
[![X URL](https://img.shields.io/twitter/url?url=https%3A%2F%2Ftwitter.com%2Fparadedb&label=Follow%20%40paradedb)](https://x.com/paradedb)
3030

31-
[ParadeDB](https://paradedb.com) integration for SQLAlchemy: typed helpers for BM25 indexes, search predicates, scoring, snippets, facets, and migration ergonomics.
31+
The official [SQLAlchemy](https://www.sqlalchemy.org/) integration for [ParadeDB](https://paradedb.com) including first class support for for managing BM25 indexes with Alembic and running queries using the full ParadeDB API.
32+
33+
## Usage
34+
35+
Follow the [getting started guide](https://docs.paradedb.com/documentation/getting-started/environment#sqlalchemy) to begin.
3236

3337
## Requirements & Compatibility
3438

@@ -39,265 +43,6 @@
3943
| ParadeDB | 0.22.0+ |
4044
| PostgreSQL | 15+ (with ParadeDB extension) |
4145

42-
## Installation
43-
44-
```bash
45-
uv add sqlalchemy-paradedb
46-
```
47-
48-
For local development:
49-
50-
```bash
51-
uv sync --extra test --extra dev
52-
```
53-
54-
## Quick Start
55-
56-
### Prerequisites
57-
58-
Install `pg_search` in your Postgres database and connect SQLAlchemy to that database.
59-
60-
### Create a BM25 Index
61-
62-
```python
63-
from sqlalchemy import Index
64-
from paradedb.sqlalchemy import indexing
65-
66-
products_bm25_idx = Index(
67-
"products_bm25_idx",
68-
indexing.BM25Field(Product.id),
69-
indexing.BM25Field(
70-
Product.description,
71-
tokenizer=indexing.tokenize.unicode(lowercase=True),
72-
),
73-
indexing.BM25Field(
74-
Product.category,
75-
tokenizer=indexing.tokenize.literal(),
76-
),
77-
postgresql_using="bm25",
78-
postgresql_with={"key_field": "id"},
79-
)
80-
```
81-
82-
For JSON columns named `metadata`, use `metadata_` as the ORM attribute name.
83-
84-
### Query with ParadeDB Predicates
85-
86-
```python
87-
from sqlalchemy import select
88-
from sqlalchemy.orm import Session
89-
from paradedb.sqlalchemy import pdb, search
90-
91-
stmt = (
92-
select(Product.id, Product.description)
93-
.where(search.match_any(Product.description, "running", "shoes"))
94-
.order_by(pdb.score(Product.id).desc())
95-
.limit(10)
96-
)
97-
98-
with Session(engine) as session:
99-
rows = session.execute(stmt).all()
100-
```
101-
102-
### Rows + Facets in a Single Query
103-
104-
```python
105-
from sqlalchemy import select
106-
from sqlalchemy.orm import Session
107-
from paradedb.sqlalchemy import facets, search
108-
109-
base = (
110-
select(Product.id, Product.description)
111-
.where(search.match_all(Product.description, "running"))
112-
.order_by(Product.id)
113-
.limit(10)
114-
)
115-
116-
stmt = facets.with_rows(
117-
base,
118-
agg=facets.multi(
119-
facets.value_count(field="id"),
120-
facets.terms(field="category", size=10),
121-
),
122-
key_field=Product.id,
123-
)
124-
125-
with Session(engine) as session:
126-
rows = session.execute(stmt).all()
127-
facet_payload = facets.extract(rows)
128-
```
129-
130-
## Search Patterns
131-
132-
### Fuzzy Matching
133-
134-
```python
135-
from paradedb.sqlalchemy import search
136-
137-
search.term(Product.description, "shose", distance=1)
138-
search.match_any(Product.description, "wirless", distance=1, prefix=True)
139-
search.term(Product.description, "rnnuing", distance=1, transpose_cost_one=True)
140-
```
141-
142-
Use fuzzy options on `term`, `match_any`, or `match_all`; there is no separate `search.fuzzy(...)` helper.
143-
144-
### Phrase Prefix and More-Like-This
145-
146-
```python
147-
from paradedb.sqlalchemy import search
148-
149-
search.phrase_prefix(Product.description, ["running", "sh"])
150-
search.more_like_this(Product.id, document_id=1, fields=["description"])
151-
```
152-
153-
### Proximity Composition
154-
155-
```python
156-
from sqlalchemy import select
157-
from paradedb.sqlalchemy import search
158-
159-
prox = search.prox_array("running").within(1, search.prox_regex("sho.*"), ordered=True)
160-
stmt = select(Product.id).where(search.proximity(Product.description, prox))
161-
```
162-
163-
## Indexing and Tokenizers
164-
165-
Tokenizer config can be expressed as a structured mapping:
166-
167-
```python
168-
from sqlalchemy import Index
169-
from paradedb.sqlalchemy import indexing
170-
171-
products_bm25_idx = Index(
172-
"products_bm25_idx",
173-
indexing.BM25Field(Product.id),
174-
indexing.BM25Field(
175-
Product.description,
176-
tokenizer=indexing.tokenize.from_config(
177-
{
178-
"tokenizer": "simple",
179-
"filters": ["lowercase", "stemmer"],
180-
"stemmer": "english",
181-
"alias": "description_simple",
182-
}
183-
),
184-
),
185-
indexing.BM25Field(
186-
Product.description,
187-
tokenizer=indexing.tokenize.from_config(
188-
{
189-
"tokenizer": "ngram",
190-
"args": [3, 8],
191-
"named_args": {"prefix_only": True},
192-
"alias": "description_ngram",
193-
}
194-
),
195-
),
196-
postgresql_using="bm25",
197-
postgresql_with={"key_field": "id"},
198-
)
199-
```
200-
201-
Validate that a field is indexed with the expected tokenizer:
202-
203-
```python
204-
from paradedb.sqlalchemy import indexing
205-
206-
indexing.assert_indexed(engine, Product.category, tokenizer="literal")
207-
```
208-
209-
Inspect BM25 metadata for a mapped table:
210-
211-
```python
212-
from paradedb.sqlalchemy import indexing
213-
214-
meta = indexing.describe(engine, Product.__table__)
215-
```
216-
217-
## Alembic Operations
218-
219-
Import once in migration environment startup so Alembic registers ParadeDB operations:
220-
221-
```python
222-
import paradedb.sqlalchemy.alembic # noqa: F401
223-
```
224-
225-
Use custom operations in migrations:
226-
227-
```python
228-
op.create_bm25_index(
229-
"products_bm25_idx",
230-
"products",
231-
["id", "description"],
232-
key_field="id",
233-
table_schema="public",
234-
)
235-
op.reindex_bm25("products_bm25_idx", concurrently=True, schema="public")
236-
op.drop_bm25_index("products_bm25_idx", if_exists=True, schema="public")
237-
```
238-
239-
`op.reindex_bm25(..., concurrently=True)` must run outside a transaction (autocommit block).
240-
241-
## Diagnostics Helpers
242-
243-
`paradedb.sqlalchemy.diagnostics` exposes wrapper functions for ParadeDB diagnostics:
244-
245-
```python
246-
from paradedb.sqlalchemy import diagnostics
247-
248-
indexes = diagnostics.paradedb_indexes(engine)
249-
segments = diagnostics.paradedb_index_segments(engine, "products_bm25_idx")
250-
check = diagnostics.paradedb_verify_index(engine, "products_bm25_idx", sample_rate=0.1)
251-
all_checks = diagnostics.paradedb_verify_all_indexes(engine, schema_pattern="public")
252-
```
253-
254-
## Common Errors
255-
256-
### `with_rows requires ORDER BY`
257-
258-
```python
259-
from sqlalchemy import select
260-
from paradedb.sqlalchemy import facets
261-
262-
# Missing order_by(...)
263-
base = select(Product.id).limit(10)
264-
facets.with_rows(base, agg=facets.value_count(field="id"), key_field=Product.id)
265-
```
266-
267-
### `with_rows requires LIMIT`
268-
269-
```python
270-
from sqlalchemy import select
271-
from paradedb.sqlalchemy import facets
272-
273-
# Missing limit(...)
274-
base = select(Product.id).order_by(Product.id)
275-
facets.with_rows(base, agg=facets.value_count(field="id"), key_field=Product.id)
276-
```
277-
278-
### `with_rows requires a ParadeDB predicate`
279-
280-
```python
281-
from sqlalchemy import select
282-
from paradedb.sqlalchemy import facets
283-
284-
# ensure_predicate=False disables automatic search.all(...) injection
285-
facets.with_rows(
286-
select(Product.id).order_by(Product.id).limit(10),
287-
agg=facets.value_count(field="id"),
288-
key_field=Product.id,
289-
ensure_predicate=False,
290-
)
291-
```
292-
293-
### `tokenizer config requires 'tokenizer'`
294-
295-
```python
296-
from paradedb.sqlalchemy import indexing
297-
298-
indexing.tokenize.from_config({"filters": ["lowercase"]})
299-
```
300-
30146
## Examples
30247

30348
- [Quick Start](examples/quickstart/quickstart.py)
@@ -307,11 +52,6 @@ indexing.tokenize.from_config({"filters": ["lowercase"]})
30752
- [Hybrid Search (RRF)](examples/hybrid_rrf/hybrid_rrf.py)
30853
- [RAG](examples/rag/rag.py)
30954

310-
## Documentation
311-
312-
- **ParadeDB Official Docs**: <https://docs.paradedb.com>
313-
- **ParadeDB Website**: <https://paradedb.com>
314-
31555
## Contributing
31656

31757
See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, running tests, linting, and the PR workflow.

0 commit comments

Comments
 (0)