Reading the index

Before you audit anything, it helps to know what you are looking at. The Overview screen answers three questions: how big the index is, what it is made of, and how much of the site is in it.

How the index is shaped

Craft’s searchindex table holds one row per searchable thing per element per site — not one row per element. An entry with a title, a body field and a summary field has three rows in each site it exists in. Each row is:

ColumnWhat it holds
elementIdThe element the row belongs to
attributetitle, slug, field, and so on
fieldIdThe field, when the attribute is field; otherwise 0
siteIdThe site — keywords are normalized in that site’s language
keywordsThe normalized, space-padded text that searches actually match against

The padding matters: Craft stores keywords with a leading and trailing space so a LIKE clause can match whole words. It is also why a row can hit the column’s storage ceiling and get cut off — see truncated keywords.

Size and composition

The Overview screen breaks the table down three ways:

  • By site — a multi-site install where one site has a fraction of the rows of another usually means that site was never fully indexed.
  • By attribute — how many rows are titles, how many are fields, how many are attributes you may not have known were searchable.
  • By field — which fields carry the most keywords. A field you thought was searchable but which has no rows at all is worth a look.

Coverage

Coverage is the number that usually starts an investigation: for each element type, how many elements exist, and how many of them have any index rows at all in each site.

A healthy site is at or very near 100% for every type that should be searchable. Anything materially below that means elements were created without being indexed — almost always an import, a migration, or a period when the queue was not running.

Coverage counts any row. An element with a title row but no field rows counts as covered here; finding those is the partly indexed elements check’s job.

The pending queue

Craft 5.7 and later defer some reindexing to a queue table rather than doing it in the request. The Overview screen shows what is waiting there, and how much of it is reserved — claimed by a worker that may or may not still be alive. A large reserved count that never goes down is the signature of a worker that died mid-job; see repairs.

Per-element detail

From the search console, or by element ID, you can open a single element and see every index row it has, with a word-by-word diff against what Craft would write for it right now. Rows come back in one of four states:

StateMeans
MatchesStored exactly as Craft would write it
DriftThe row exists but its keywords disagree with the live content
No rowCraft would write a row here and there isn’t one
ExtraA row exists that Craft would not write at all

The same comparison is available in PHP and Twig — see Twig and Extending.

From the console

# size, composition and coverage
php craft holmes/index

# every index row for one element, with the diff
php craft holmes/index/element 1234