Skip to content

Commit a92b652

Browse files
authored
feat: more stuff to code (#3)
2 parents d713372 + 08a41fa commit a92b652

28 files changed

Lines changed: 2385 additions & 172 deletions

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pip install -e .[test,dev]
1414
ruff check .
1515
mypy paradedb
1616
python -m pytest tests/unit
17-
PARADEDB_TEST_DSN=postgres://postgres:postgres@localhost:5432/postgres python -m pytest -m integration
17+
PARADEDB_TEST_DSN=postgres://postgres:postgres@localhost:5443/postgres python -m pytest -m integration
1818
```
1919

2020
## Guidelines

README.md

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pip install -e .[test,dev]
2626
- `paradedb.sqlalchemy.search`: ParadeDB predicates (`match_all`, `fuzzy`, `parse`, `more_like_this`, etc.).
2727
- `paradedb.sqlalchemy.pdb`: function wrappers (`score`, `snippet`, `snippets`, `agg`).
2828
- `paradedb.sqlalchemy.facets`: aggregate/facet JSON builders and rows+facets helper.
29-
- `paradedb.sqlalchemy.select_with`: select decorators for score/snippet columns.
29+
- `paradedb.sqlalchemy.select_with`: select decorators for score/snippet/snippet_positions columns.
3030
- `paradedb.sqlalchemy.alembic`: Alembic operations for BM25 index lifecycle.
3131

3232
## Quickstart
@@ -49,11 +49,65 @@ products_bm25_idx.create(engine)
4949
stmt = select(Product.id, Product.description).where(search.match_any(Product.description, "running", "shoes"))
5050
```
5151

52+
Index JSON keys using BM25Field expressions:
53+
54+
```python
55+
from paradedb.sqlalchemy import expr
56+
57+
products_bm25_idx = Index(
58+
"products_bm25_idx",
59+
indexing.BM25Field(Product.id),
60+
indexing.BM25Field(
61+
expr.json_text(Product.metadata, "color"),
62+
tokenizer=indexing.tokenize.literal(alias="metadata_color"),
63+
),
64+
indexing.BM25Field(
65+
expr.json_text(Product.metadata, "location"),
66+
tokenizer=indexing.tokenize.literal(alias="metadata_location"),
67+
),
68+
postgresql_using="bm25",
69+
postgresql_with={"key_field": "id"},
70+
)
71+
```
72+
73+
Tokenizer configs can use a Django/Rails-style structured shape:
74+
75+
```python
76+
products_bm25_idx = Index(
77+
"products_bm25_idx",
78+
indexing.BM25Field(Product.id),
79+
indexing.BM25Field(
80+
Product.description,
81+
tokenizer=indexing.tokenize.from_config(
82+
{
83+
"tokenizer": "simple",
84+
"filters": ["lowercase", "stemmer"],
85+
"stemmer": "english",
86+
"alias": "description_simple",
87+
}
88+
),
89+
),
90+
indexing.BM25Field(
91+
Product.description,
92+
tokenizer=indexing.tokenize.from_config(
93+
{
94+
"tokenizer": "ngram",
95+
"args": [3, 8],
96+
"named_args": {"prefix_only": True},
97+
"alias": "description_ngram",
98+
}
99+
),
100+
),
101+
postgresql_using="bm25",
102+
postgresql_with={"key_field": "id"},
103+
)
104+
```
105+
52106
## Query APIs
53107

54108
- Basic predicates: `match_all`, `match_any`, `term`, `phrase`, `fuzzy`, `regex`, `all`
55109
- Advanced predicates: `parse`, `phrase_prefix`, `regex_phrase`, `near`, `proximity`, `more_like_this`
56-
- Scoring/snippets: `pdb.score`, `pdb.snippet`, `pdb.snippets`, `select_with.score`, `select_with.snippet`
110+
- Scoring/snippets: `pdb.score`, `pdb.snippet`, `pdb.snippets`, `pdb.snippet_positions`, `select_with.score`, `select_with.snippet`, `select_with.snippet_positions`
57111
- Aggregations/facets: `facets.*` builders + `pdb.agg(...)`
58112
- Rows + facets: `facets.with_rows(...)`
59113

@@ -67,6 +121,8 @@ stmt = (
67121
select(
68122
pdb.agg(facets.value_count(field="id")).label("count"),
69123
pdb.agg(facets.avg(field="rating")).label("avg_rating"),
124+
pdb.agg(facets.percentiles(field="rating", percents=[50, 95])).label("rating_percentiles"),
125+
pdb.agg(facets.top_hits(size=2, sort=[{"rating": "desc"}], docvalue_fields=["id", "rating"])).label("top_hits"),
70126
)
71127
.select_from(Product)
72128
.where(search.match_all(Product.description, "running"))
@@ -85,8 +141,24 @@ Usage:
85141

86142
```python
87143
op.create_bm25_index("products_bm25_idx", "products", ["id", "description"], key_field="id")
144+
# Tokenizer-aware expressions are supported too:
145+
op.create_bm25_index(
146+
"products_bm25_idx",
147+
"products",
148+
["id", "((description)::pdb.simple('alias=description_simple,lowercase=true'))"],
149+
key_field="id",
150+
)
151+
# Schema-aware operations:
152+
op.create_bm25_index(
153+
"products_bm25_idx",
154+
"products",
155+
["id", "description"],
156+
key_field="id",
157+
table_schema="search",
158+
)
88159
op.reindex_bm25("products_bm25_idx", concurrently=True)
89-
op.drop_bm25_index("products_bm25_idx", if_exists=True)
160+
op.reindex_bm25("products_bm25_idx", concurrently=True, schema="search")
161+
op.drop_bm25_index("products_bm25_idx", if_exists=True, schema="search")
90162
```
91163

92164
## Validation and Guardrails
@@ -117,7 +189,7 @@ python -m pytest tests/unit
117189
Integration tests (requires running ParadeDB):
118190

119191
```bash
120-
PARADEDB_TEST_DSN=postgres://postgres:postgres@localhost:5432/postgres python -m pytest -m integration
192+
PARADEDB_TEST_DSN=postgres://postgres:postgres@localhost:5443/postgres python -m pytest -m integration
121193
```
122194

123195
## CI

examples/common.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424

2525
def engine_from_env() -> Engine:
26-
dsn = os.getenv("DATABASE_URL", "postgresql+psycopg://postgres:postgres@localhost:5432/postgres")
26+
dsn = os.getenv("DATABASE_URL", "postgresql+psycopg://postgres:postgres@localhost:5443/postgres")
2727
return create_engine(dsn)
2828

2929

examples/faceted_search.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@ def main() -> None:
2828
select(
2929
pdb.agg(facets.value_count(field="id")).label("count"),
3030
pdb.agg(facets.avg(field="rating")).label("avg_rating"),
31+
pdb.agg(facets.percentiles(field="rating", percents=[50, 95])).label("rating_percentiles"),
32+
pdb.agg(
33+
facets.top_hits(
34+
size=2,
35+
sort=[{"rating": "desc"}],
36+
docvalue_fields=["id", "rating"],
37+
)
38+
).label("top_hits"),
3139
)
3240
.select_from(Product)
3341
.where(search.match_all(Product.description, "running"))

0 commit comments

Comments
 (0)