Skip to content

Commit cacff47

Browse files
authored
docs: Simplify README (#48)
1 parent 1eb8b68 commit cacff47

1 file changed

Lines changed: 12 additions & 274 deletions

File tree

README.md

Lines changed: 12 additions & 274 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,21 @@
1616
<a href="https://docs.paradedb.com/changelog/">Changelog</a>
1717
</h3>
1818

19-
---
19+
<p align="center">
20+
<a href="https://pypi.org/project/sqlalchemy-paradedb/"><img src="https://img.shields.io/pypi/v/sqlalchemy-paradedb" alt="PyPI"></a>&nbsp;
21+
<a href="https://pypi.org/project/sqlalchemy-paradedb/"><img src="https://img.shields.io/pypi/pyversions/sqlalchemy-paradedb" alt="Python Versions"></a>&nbsp;
22+
<a href="https://pypi.org/project/sqlalchemy-paradedb/"><img src="https://img.shields.io/pypi/dm/sqlalchemy-paradedb" alt="Downloads"></a>&nbsp;
23+
<a href="https://codecov.io/gh/paradedb/sqlalchemy-paradedb"><img src="https://codecov.io/gh/paradedb/sqlalchemy-paradedb/graph/badge.svg" alt="Codecov"></a>&nbsp;
24+
<a href="https://github.com/paradedb/sqlalchemy-paradedb?tab=MIT-1-ov-file#readme"><img src="https://img.shields.io/github/license/paradedb/sqlalchemy-paradedb?color=blue" alt="License"></a>&nbsp;
25+
<a href="https://paradedb.com/slack"><img src="https://img.shields.io/badge/Join%20Slack-purple?logo=slack" alt="Community"></a>&nbsp;
26+
<a href="https://x.com/paradedb"><img src="https://img.shields.io/twitter/url?url=https%3A%2F%2Ftwitter.com%2Fparadedb&label=Follow%20%40paradedb" alt="Follow @paradedb"></a>
27+
</p>
2028

21-
# sqlalchemy-paradedb
29+
---
2230

23-
[![PyPI](https://img.shields.io/pypi/v/sqlalchemy-paradedb)](https://pypi.org/project/sqlalchemy-paradedb/)
24-
[![Python Versions](https://img.shields.io/pypi/pyversions/sqlalchemy-paradedb)](https://pypi.org/project/sqlalchemy-paradedb/)
25-
[![Downloads](https://img.shields.io/pypi/dm/sqlalchemy-paradedb)](https://pypi.org/project/sqlalchemy-paradedb/)
26-
[![Codecov](https://codecov.io/gh/paradedb/sqlalchemy-paradedb/graph/badge.svg)](https://codecov.io/gh/paradedb/sqlalchemy-paradedb)
27-
[![License](https://img.shields.io/github/license/paradedb/sqlalchemy-paradedb?color=blue)](https://github.com/paradedb/sqlalchemy-paradedb?tab=MIT-1-ov-file#readme)
28-
[![Slack URL](https://img.shields.io/badge/Join%20Slack-purple?logo=slack&link=https%3A%2F%2Fparadedb.com%2Fslack)](https://paradedb.com/slack)
29-
[![X URL](https://img.shields.io/twitter/url?url=https%3A%2F%2Ftwitter.com%2Fparadedb&label=Follow%20%40paradedb)](https://x.com/paradedb)
31+
## ParadeDB for SQLAlchemy
3032

31-
[ParadeDB](https://paradedb.com) integration for SQLAlchemy: typed helpers for BM25 indexes, search predicates, scoring, snippets, facets, and migration ergonomics.
33+
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. Follow the [getting started guide](https://docs.paradedb.com/documentation/getting-started/environment#sqlalchemy) to begin.
3234

3335
## Requirements & Compatibility
3436

@@ -39,265 +41,6 @@
3941
| ParadeDB | 0.22.0+ |
4042
| PostgreSQL | 15+ (with ParadeDB extension) |
4143

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-
30144
## Examples
30245

30346
- [Quick Start](examples/quickstart/quickstart.py)
@@ -307,11 +50,6 @@ indexing.tokenize.from_config({"filters": ["lowercase"]})
30750
- [Hybrid Search (RRF)](examples/hybrid_rrf/hybrid_rrf.py)
30851
- [RAG](examples/rag/rag.py)
30952

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

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

0 commit comments

Comments
 (0)