docs/documentation/indexing/indexing-expressions.mdx
In addition to indexing columns, Postgres expressions can also be indexed.
The following statement indexes an expression which concatenates description and category, which are both text fields:
from django.db import connection, models
from django.db.models import F, Func, Value
from paradedb.indexes import BM25Index, IndexExpression
with connection.schema_editor() as schema_editor:
schema_editor.add_index(
MockItem,
BM25Index(
fields={"id": {}},
expressions=[
IndexExpression(
Func(
F("description"),
Value(" "),
F("category"),
template="(%(expressions)s)",
arg_joiner=" || ",
output_field=models.TextField(),
),
alias="description_concat",
tokenizer="simple",
),
],
key_field="id",
name="search_idx",
),
)
from sqlalchemy import Index
from paradedb.sqlalchemy import indexing
idx = Index(
"search_idx",
indexing.BM25Field(MockItem.id),
indexing.BM25Field(
MockItem.description + " " + MockItem.category,
tokenizer=indexing.tokenize.simple(alias="description_concat"),
),
postgresql_using="bm25",
postgresql_with={"key_field": "id"},
)
with engine.begin() as conn:
idx.create(conn)
ActiveRecord::Base.connection.add_bm25_index(
:mock_items,
fields: {
id: {},
"(description || ' ' || category)" => {
tokenizer: :simple,
alias: "description_concat"
}
},
key_field: :id,
name: :search_idx
)
To index a text/JSON expression:
description || ' ' || category.pdb.simple.alias=<alias_name> to the tokenizer.Querying against the expression is the same as querying a regular field:
SELECT description, rating, category
FROM mock_items
WHERE (description || ' ' || category) &&& 'running shoes';
To index a non-text expression, cast the expression to pdb.alias. For example, the following statement indexes
the expression rating + 1, which returns an integer:
from django.db import connection
from django.db.models import F
from paradedb.indexes import BM25Index, IndexExpression
with connection.schema_editor() as schema_editor:
schema_editor.add_index(
MockItem,
BM25Index(
fields={"id": {}, "description": {}},
expressions=[
IndexExpression(
F("rating") + 1,
alias="rating",
),
],
key_field="id",
name="search_idx",
),
)
from sqlalchemy import Index
from paradedb.sqlalchemy import indexing, pdb
idx = Index(
"search_idx",
indexing.BM25Field(MockItem.id),
indexing.BM25Field(MockItem.description),
indexing.BM25Field(
pdb.alias(MockItem.rating + 1, "rating"),
),
postgresql_using="bm25",
postgresql_with={"key_field": "id"},
)
with engine.begin() as conn:
idx.create(conn)
ActiveRecord::Base.connection.add_bm25_index(
:mock_items,
fields: {
id: {},
description: {},
"(rating + 1)" => { alias: "rating" }
},
key_field: :id,
name: :search_idx
)
With the expression indexed, queries containing the expression can be pushed down to the ParadeDB index:
SELECT description, rating, category
FROM mock_items
WHERE description &&& 'running shoes'
AND rating + 1 > 3;