> ## 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.

# Partial Indexes

> Add row filters to the BM25 index

A partial index is an index that only includes rows that satisfy a `WHERE` condition.
Instead of indexing every row in a table, Postgres evaluates the predicate and only indexes rows that match it.
This can reduce index size and improve performance when you only query a subset of a table.

The BM25 index supports partial indexes using the same syntax as PostgreSQL.

<CodeGroup>
  ```sql SQL theme={null}
  CREATE INDEX search_idx ON mock_items
  USING bm25 (id, description, category)
  WITH (key_field='id')
  WHERE description IS NOT NULL;
  ```

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

  indexing
    .bm25Index("search_idx")
    .on(mockItems.id, mockItems.description, mockItems.category)
    .where(isNotNull(mockItems.description));
  ```

  ```python Django theme={null}
  from django.db import connection
  from django.db.models import Q
  from paradedb.indexes import BM25Index

  with connection.schema_editor() as schema_editor:
      schema_editor.add_index(
          MockItem,
          BM25Index(
              fields={
                  "id": {},
                  "description": {},
                  "category": {},
              },
              key_field="id",
              name="search_idx",
              condition=Q(description__isnull=False),
          ),
      )
  ```

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

  idx = Index(
      "search_idx",
      indexing.BM25Field(MockItem.id),
      indexing.BM25Field(MockItem.description),
      indexing.BM25Field(MockItem.category),
      postgresql_using="bm25",
      postgresql_with={"key_field": "id"},
      postgresql_where=MockItem.description.is_not(None),
  )

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

  ```ruby Rails theme={null}
  ActiveRecord::Base.connection.add_bm25_index(
    :mock_items,
    fields: {
      id: {},
      description: {},
      category: {}
    },
    key_field: :id,
    name: :search_idx,
    where: "description IS NOT NULL"
  )
  ```

  ```cs EF Core theme={null}
  modelBuilder.Entity<MockItem>()
      .HasBm25Index("search_idx", e => e.Id)
      .HasField(e => e.Description)
      .HasField(e => e.Category)
      .HasFilter("description IS NOT NULL");
  ```
</CodeGroup>

An important note: if the BM25 index has a `WHERE` condition, queries **must have the same `WHERE` condition** in order for the index to be used.
A query that does not contain the `WHERE` condition will fall back to a sequential scan, which does not support all of
ParadeDB's query types and has poor performance.

For example, the following query will not use the partial BM25 index defined above because it does not contain the
`description IS NOT NULL` predicate:

```sql theme={null}
SELECT * FROM mock_items
WHERE description ||| 'running shoes';
```

However, this query will use the BM25 index because it contains the predicate:

```sql theme={null}
SELECT * FROM mock_items
WHERE description ||| 'running shoes'
AND description IS NOT NULL;
```

This behavior is consistent with other Postgres indexes and is necessary to ensure that the index returns correct results.
