Queryable or Searchable? How indexing type changes your Optimizely Graph query

You have a page in Optimizely CMS. The title is Optimizely Graph indexing guide, and you filter that title from Optimizely Graph with like, using the letters dex from the word indexing.

With the title property set to Queryable, this query returns the page:

where: { Title: { like: "%dex%" } }

like matches dex inside the word indexing.

Set that same property to Searchable and run the query again. The query stays valid. The result is empty. On a searchable field, like matches only the start of a token. The tokens here are Optimizely, Graph, indexing, and guide. None of them starts with dex.

where: { Title: { like: "%index%" } }

This one returns the page, because the token indexing starts with index.

That difference is Property Indexing Type. Each CMS property is Default, Queryable, Searchable, or Disabled. Optimizely Graph uses it to decide whether the value is returned, allowed in where, included in full-text search, or left out of the schema.

Searchable adds match and contains. It also removes endsWith and changes what like matches. The next sections take each indexing type in turn, with the query that shows the difference.

What GraphiQL lists for each indexing type

The Title filter above changes with the indexing type because GraphiQL shows a different operator list for each one. Store Optimizely Graph indexing guide in three properties on the same page and open that page type.

PropertyIndexing type
DisplayTitleDefault
FilterTitleQueryable
SearchTitleSearchable

Under items, all three are available. Default still returns the value.

{
  ArticlePage {
    items {
      DisplayTitle
      FilterTitle
      SearchTitle
    }
  }
}

Each one comes back as Optimizely Graph indexing guide.

Under where, DisplayTitle is missing. A Default property has no filter input, so this query fails validation:

where: { DisplayTitle: { eq: "Optimizely Graph indexing guide" } }

Shared by FilterTitle and SearchTitle

eq, notEq, in, notIn, startsWith, like, exist, fuzzy, boost, synonyms

Only FilterTitle (Queryable)

endsWith

Only SearchTitle (Searchable)

match, contains

Same operator, different match

like on FilterTitle matches inside a word, as with dex in indexing. like on SearchTitle matches the start of a token, as with index in indexing.

Disabled

A Disabled property is absent from items and from where.

Run the filters

Each query below uses Optimizely Graph indexing guide.

Exact match. Both indexed fields return the page.

{
  byQueryable: ArticlePage(where: { FilterTitle: { eq: "Optimizely Graph indexing guide" } }) {
    total
  }
  bySearchable: ArticlePage(where: { SearchTitle: { eq: "Optimizely Graph indexing guide" } }) {
    total
  }
}

Both return "total": 1.

like inside a word. Only the queryable field hits.

{
  queryableMidWord: ArticlePage(where: { FilterTitle: { like: "%dex%" } }) {
    total
  }
  searchableMidWord: ArticlePage(where: { SearchTitle: { like: "%dex%" } }) {
    total
  }
}

queryableMidWord returns 1. searchableMidWord stays valid and returns 0.

like from the start of a token. The searchable field hits.

{
  ArticlePage(where: { SearchTitle: { like: "%index%" } }) {
    total
  }
}

Returns 1, because the token indexing starts with index.

endsWith. Queryable only.

{
  ArticlePage(where: { FilterTitle: { endsWith: "guide" } }) {
    total
  }
}

Returns 1. The same operator on SearchTitle is a schema error.

match. Searchable only.

{
  ArticlePage(where: { SearchTitle: { match: "indexing guide" } }) {
    items {
      SearchTitle
      _score
    }
  }
}


Returns the page. The same operator on FilterTitle is a schema error.

Search every searchable field with _fulltext

_fulltext is a field Optimizely Graph adds to the page type. It contains the searchable properties only. DisplayTitle and FilterTitle stay out of it.

{
  ArticlePage(
    where: { _fulltext: { match: "indexing" } }
    orderBy: { _ranking: RELEVANCE }
  ) {
    items {
      DisplayTitle
      _fulltext
      _score
    }
  }
}

The page comes back. _fulltext includes Optimizely Graph indexing guide from SearchTitle. One match on _fulltext covers every searchable property on that page, including nested ones.

Compare the four indexing types

Shared filters means eq, notEq, in, notIn, startsWith, exist, fuzzy, boost, and synonyms.

Final thoughts

Use Default when the page only needs to display the value. Use Queryable when a listing filters, sorts, or facets on it, including endsWith and a like match inside a word. Use Searchable when the value should drive site search through match, contains, and _fulltext. Use Disabled when the value should stay out of Graph.

Searchable is a different index from Queryable. Moving a field from Queryable to Searchable adds match and contains, removes endsWith, and changes like. Check the filters already written against that field before you change it.

In code-first, leave indexingType off for Default. The API has no "default" value.

Yes. This covers what the four indexing types change in a GraphQL query: what you can read, what you can filter, and what full-text search includes.

Happy Optimizing!!!

Leave a comment