Skip to content

Use Semantic Search

⏱ 25 minutes advanced
📜CoreGraph

Keyword search finds content that contains exact terms. Semantic search finds content that matches the meaning of a query, even when the exact words differ. A search for “how to reduce costs” can surface articles about “budget optimization” or “expense management” because Graph understands the semantic similarity.

This is particularly valuable for content-rich sites where users phrase their needs differently from the terminology authors used.

Semantic search requires activation on your Graph subscription. It uses vector embeddings to represent content meaning, which requires additional processing during indexing.

Once enabled, Graph automatically generates vector embeddings for all indexed content during the next full sync. Incremental syncs generate embeddings for new and updated content.

Use the SEMANTIC ranking mode to rank results by meaning similarity instead of keyword frequency.

Basic semantic search
graphql
query SemanticSearch {
  ArticlePage(
    where: {
      _fulltext: { contains: "how to reduce operational costs" }
    }
    orderBy: { _ranking: SEMANTIC }
    limit: 10
  ) {
    items {
      Headline
      Summary
      _score
      _metadata {
        url { default }
      }
    }
    total
  }
}

The _score field reflects semantic similarity — higher values indicate closer meaning alignment with the query.

Section titled “Step 3: Combine semantic with keyword search”

For the best results, combine semantic understanding with keyword precision. Graph supports a hybrid approach that uses both scoring methods.

Hybrid semantic + keyword search
graphql
query HybridSearch($query: String!) {
  ArticlePage(
    where: {
      _fulltext: {
        contains: $query
        match: SEMANTIC_AND_KEYWORD
      }
    }
    orderBy: { _ranking: RELEVANCE }
    limit: 10
  ) {
    items {
      Headline
      Summary
      _score
    }
    total
  }
}

Hybrid search ranks results using a weighted combination of keyword relevance and semantic similarity. Content that matches both dimensions ranks highest.

Step 4: Scope semantic search to specific fields

Section titled “Step 4: Scope semantic search to specific fields”

By default, semantic search considers all full-text indexed fields. You can focus the semantic analysis on specific fields for more precise results.

Field-scoped semantic search
graphql
query ScopedSemanticSearch {
  ArticlePage(
    where: {
      _fulltext: {
        contains: "machine learning applications"
        boost: {
          Headline: 3
          Summary: 2
          ArticleBody: 1
        }
      }
    }
    orderBy: { _ranking: SEMANTIC }
    limit: 10
  ) {
    items {
      Headline
      Summary
      _score
    }
  }
}

Semantic search combines with all standard Graph filters. Apply filters first to narrow the candidate set, then rank semantically within that set.

Filtered semantic search
graphql
query FilteredSemanticSearch($query: String!, $category: String!) {
  ArticlePage(
    where: {
      _fulltext: { contains: $query }
      Category: { eq: $category }
      _metadata: {
        published: { gte: "2025-01-01T00:00:00Z" }
        status: { eq: "Published" }
      }
    }
    orderBy: { _ranking: SEMANTIC }
    limit: 10
  ) {
    items {
      Headline
      Category
      _score
      _metadata { published }
    }
    total
    facets {
      Category { name count }
    }
  }
}

Step 6: Implement a frontend semantic search UI

Section titled “Step 6: Implement a frontend semantic search UI”

Integrate semantic search into a React component that provides a natural-language search experience.

React semantic search component
javascript
import { useState, useCallback } from 'react';
import debounce from 'lodash/debounce';

export function SemanticSearch() {
  const [results, setResults] = useState([]);
  const [loading, setLoading] = useState(false);

  const search = useCallback(
    debounce(async (query) => {
      if (!query || query.length < 3) return;
      setLoading(true);

      const response = await fetch(GRAPH_URL, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${SINGLE_KEY}`,
        },
        body: JSON.stringify({
          query: SEMANTIC_QUERY,
          variables: { query },
        }),
      });

      const { data } = await response.json();
      setResults(data.ArticlePage.items);
      setLoading(false);
    }, 300),
    []
  );

  return (
    <div>
      <input
        type="search"
        placeholder="Ask a question..."
        onChange={(e) => search(e.target.value)}
      />
      {results.map((item) => (
        <article key={item._metadata.url.default}>
          <h3>{item.Headline}</h3>
          <p>{item.Summary}</p>
          <span>Relevance: {Math.round(item._score * 100)}%</span>
        </article>
      ))}
    </div>
  );
}
  • Embedding generation — Semantic indexing adds time to content sync. Expect slightly longer sync durations compared to keyword-only indexing.
  • Query latency — Semantic queries take marginally longer than keyword queries due to vector similarity computation. Typical overhead is 50-100ms.
  • Cost — Semantic search uses additional compute resources. Monitor usage through the Optimizely portal.