> ## Documentation Index
> Fetch the complete documentation index at: https://docs.paradedb.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Indexing Expressions

> Add Postgres expressions to the index

In addition to indexing columns, Postgres expressions can also be indexed.

## Indexing Text/JSON Expressions

The following statement indexes an expression which concatenates `description` and `category`, which are both text fields:

<CodeGroup>
  ```sql SQL theme={null}
  CREATE INDEX search_idx ON mock_items
  USING bm25 (id, ((description || ' ' || category)::pdb.simple('alias=description_concat')))
  WITH (key_field='id');
  ```

  ```ts Drizzle theme={null}
  import { sql } from "drizzle-orm";
  import { indexing, tokenizer } from "@paradedb/drizzle-paradedb";

  indexing
    .bm25Index("search_idx")
    .on(
      mockItems.id,
      indexing.bm25Field(
        sql`${mockItems.description} || ' ' || ${mockItems.category}`,
        tokenizer.simple({ alias: "description_concat" }),
      ),
    );
  ```

  ```python Django theme={null}
  from django.db import connection, models
  from django.db.models import F, Func, Value
  from paradedb.indexes import BM25Index, IndexExpression
  from paradedb.search import Tokenizer

  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=Tokenizer.simple(
                          options={"alias": "description_concat"}
                      ),
                  ),
              ],
              key_field="id",
              name="search_idx",
          ),
      )
  ```

  ```python SQLAlchemy theme={null}
  from sqlalchemy import Index
  from paradedb.sqlalchemy import indexing, tokenizer

  idx = Index(
      "search_idx",
      indexing.BM25Field(MockItem.id),
      indexing.BM25Field(
          MockItem.description + " " + MockItem.category,
          tokenizer=tokenizer.simple(options={"alias": "description_concat"}),
      ),
      postgresql_using="bm25",
      postgresql_with={"key_field": "id"},
  )

  with engine.begin() as conn:
      idx.create(conn)
  ```

  ```ruby Rails theme={null}
  ActiveRecord::Base.connection.add_bm25_index(
    :mock_items,
    fields: {
      id: {},
      "(description || ' ' || category)" => {
        tokenizer: ParadeDB::Tokenizer.simple(options: { alias: "description_concat" })
      }
    },
    key_field: :id,
    name: :search_idx
  )
  ```

  ```cs EF Core theme={null}
  modelBuilder.Entity<MockItem>()
      .HasBm25Index("search_idx", e => e.Id)
      .HasField(
          "description || ' ' || category",
          Tokenizer.Simple(new() { ["alias"] = "description_concat" })
      );
  ```
</CodeGroup>

To index a text/JSON expression:

1. Add the expression to the column list. In this example, the expression is `description || ' ' || category`.
2. Cast it to a [tokenizer](/documentation/tokenizers/overview), in this example `pdb.simple`.
3. ParadeDB will try and infer a field name based on the field used in the expression. However,
   if the field name cannot be inferred (e.g. because the expression involves more than one field), you will be required
   to add an `alias=<alias_name>` to the tokenizer.

Querying against the expression is the same as querying a regular field:

```sql theme={null}
SELECT description, rating, category
FROM mock_items
WHERE (description || ' ' || category) &&& 'running shoes';
```

<Note>
  The expression on the left-hand side of the operator must exactly match the
  expression that was indexed.
</Note>

## Indexing Non-Text Expressions

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:

<CodeGroup>
  ```sql SQL theme={null}
  CREATE INDEX search_idx ON mock_items
  USING bm25 (id, description, ((rating + 1)::pdb.alias('rating')))
  WITH (key_field='id');
  ```

  ```ts Drizzle theme={null}
  import { sql } from "drizzle-orm";
  import { indexing, search } from "@paradedb/drizzle-paradedb";

  indexing
    .bm25Index("search_idx")
    .on(
      mockItems.id,
      mockItems.description,
      search.alias(sql`${mockItems.rating} + 1`, "rating"),
    );
  ```

  ```python Django theme={null}
  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",
          ),
      )
  ```

  ```python SQLAlchemy theme={null}
  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)
  ```

  ```ruby Rails theme={null}
  ActiveRecord::Base.connection.add_bm25_index(
    :mock_items,
    fields: {
      id: {},
      description: {},
      "(rating + 1)" => { alias: "rating" }
    },
    key_field: :id,
    name: :search_idx
  )
  ```

  ```cs EF Core theme={null}
  modelBuilder.Entity<MockItem>()
      .HasBm25Index("search_idx", e => e.Id)
      .HasField(e => e.Description)
      .HasField("rating + 1", new FieldAlias("rating"));
  ```
</CodeGroup>

With the expression indexed, queries containing the expression can be pushed down to the ParadeDB index:

```sql theme={null}
SELECT description, rating, category
FROM mock_items
WHERE description &&& 'running shoes'
AND rating + 1 > 3;
```
