<!-- CANARY: REQ=REQ-GQL-016; FEATURE="MultiIndexOptimizer"; ASPECT=IndexTypeSelection; STATUS=TESTED; OWNER=engine; UPDATED=2025-10-03 -->
<h2 id="index-optimization-tutorial" class="position-relative d-flex align-items-center group">
<span>Index Optimization Tutorial</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="index-optimization-tutorial"
aria-haspopup="dialog"
aria-label="Share link: Index Optimization Tutorial">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h2><div id="headingShareModal" class="heading-share-modal" role="dialog" aria-modal="true" aria-labelledby="headingShareTitle" hidden>
<div class="hsm-dialog" role="document">
<div class="hsm-header">
<h2 id="headingShareTitle" class="h6 mb-0 fw-bold">Share this section</h2>
<button type="button" class="hsm-close" aria-label="Close">
<i class="fa-solid fa-xmark"></i>
</button>
</div>
<div class="hsm-body">
<label for="headingShareInput" class="form-label small text-muted mb-1 text-uppercase fw-bold" style="font-size: 0.7rem; letter-spacing: 0.5px;">Permalink</label>
<div class="input-group mb-4 hsm-url-group">
<input id="headingShareInput" type="text" class="form-control font-monospace" readonly aria-readonly="true" style="font-size: 0.85rem;" />
<button class="btn btn-primary hsm-copy" type="button" aria-label="Copy" title="Copy">
<i class="fa-duotone fa-clipboard" aria-hidden="true"></i>
</button>
</div>
<div class="small fw-bold mb-2 text-muted text-uppercase" style="font-size: 0.7rem; letter-spacing: 0.5px;">Share via</div>
<div class="hsm-share-grid">
<a id="share-twitter" class="btn btn-outline-secondary w-100" target="_blank" rel="noopener noreferrer">
<i class="fa-brands fa-twitter me-2"></i>Twitter
</a>
<a id="share-linkedin" class="btn btn-outline-secondary w-100" target="_blank" rel="noopener noreferrer">
<i class="fa-brands fa-linkedin me-2"></i>LinkedIn
</a>
<a id="share-facebook" class="btn btn-outline-secondary w-100" target="_blank" rel="noopener noreferrer">
<i class="fa-brands fa-facebook me-2"></i>Facebook
</a>
</div>
</div>
</div>
</div>
<style>
.heading-share-modal {
position: fixed;
inset: 0;
display: flex;
justify-content: center;
align-items: center;
background: rgba(0, 0, 0, 0.6);
z-index: 1050;
padding: 1rem;
backdrop-filter: blur(4px);
-webkit-backdrop-filter: blur(4px);
}
.heading-share-modal[hidden] { display: none !important; }
.hsm-dialog {
max-width: 420px;
width: 100%;
background: var(--bs-body-bg, #fff);
color: var(--bs-body-color, #212529);
border: 1px solid var(--bs-border-color, rgba(0,0,0,0.1));
border-radius: 1rem;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
overflow: hidden;
animation: hsm-fade-in 0.2s ease-out;
}
@keyframes hsm-fade-in {
from { opacity: 0; transform: scale(0.95); }
to { opacity: 1; transform: scale(1); }
}
[data-bs-theme="dark"] .hsm-dialog {
background: #1e293b;
border-color: rgba(255,255,255,0.1);
color: #f8f9fa;
}
.hsm-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 1.5rem;
border-bottom: 1px solid var(--bs-border-color, rgba(0,0,0,0.1));
background: rgba(0,0,0,0.02);
}
[data-bs-theme="dark"] .hsm-header {
background: rgba(255,255,255,0.02);
border-color: rgba(255,255,255,0.1);
}
.hsm-close {
background: transparent;
border: none;
color: inherit;
opacity: 0.5;
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
font-size: 1.2rem;
line-height: 1;
transition: opacity 0.2s;
}
.hsm-close:hover {
opacity: 1;
}
.hsm-body {
padding: 1.5rem;
}
.hsm-url-group {
display: flex !important;
align-items: stretch;
}
.hsm-url-group .form-control {
flex: 1;
min-width: 0;
margin: 0;
background: var(--bs-secondary-bg, #f8f9fa);
border-color: var(--bs-border-color, #dee2e6);
border-top-right-radius: 0;
border-bottom-right-radius: 0;
height: 42px;
}
.hsm-url-group .btn {
flex: 0 0 auto;
margin: 0;
margin-left: -1px;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
height: 42px;
display: flex;
align-items: center;
justify-content: center;
padding: 0 1.25rem;
z-index: 2;
}
[data-bs-theme="dark"] .hsm-url-group .form-control {
background: #0f172a;
border-color: #334155;
color: #e2e8f0;
}
.hsm-share-grid {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.hsm-share-grid .btn {
display: flex;
align-items: center;
justify-content: center;
font-size: 0.9rem;
padding: 0.6rem;
border-color: var(--bs-border-color);
width: 100%;
}
[data-bs-theme="dark"] .hsm-share-grid .btn {
color: #e2e8f0;
border-color: #475569;
}
[data-bs-theme="dark"] .hsm-share-grid .btn:hover {
background: #334155;
border-color: #cbd5e1;
}
</style>
<script>
(function(){
const modal = document.getElementById('headingShareModal');
if(!modal) return;
const input = modal.querySelector('#headingShareInput');
const copyBtn = modal.querySelector('.hsm-copy');
const twitter = modal.querySelector('#share-twitter');
const linkedin = modal.querySelector('#share-linkedin');
const facebook = modal.querySelector('#share-facebook');
const closeBtn = modal.querySelector('.hsm-close');
let lastFocus=null;
let trapBound=false;
function buildUrl(id){ return window.location.origin + window.location.pathname + '#' + id; }
function isOpen(){ return !modal.hasAttribute('hidden'); }
function hydrate(id){
const url=buildUrl(id);
input.value=url;
const enc=encodeURIComponent(url);
const text=encodeURIComponent(document.title);
if(twitter) twitter.href=`https://twitter.com/intent/tweet?url=${enc}&text=${text}`;
if(linkedin) linkedin.href=`https://www.linkedin.com/sharing/share-offsite/?url=${enc}`;
if(facebook) facebook.href=`https://www.facebook.com/sharer/sharer.php?u=${enc}`;
}
function openModal(id){
lastFocus=document.activeElement;
hydrate(id);
if(!isOpen()){
modal.removeAttribute('hidden');
}
requestAnimationFrame(()=>{ input.focus(); });
trapFocus();
}
function closeModal(){
if(!isOpen()) return;
modal.setAttribute('hidden','');
if(lastFocus && typeof lastFocus.focus==='function') lastFocus.focus();
}
function copyCurrent(){
try{ navigator.clipboard.writeText(input.value).then(()=>feedback(true),()=>fallback()); }
catch(e){ fallback(); }
}
function fallback(){ input.select(); try{ document.execCommand('copy'); feedback(true);}catch(e){ feedback(false);} }
function feedback(ok){ if(!copyBtn) return; const icon=copyBtn.querySelector('i'); if(!icon) return; const prev=copyBtn.getAttribute('data-prev')||icon.className; if(!copyBtn.getAttribute('data-prev')) copyBtn.setAttribute('data-prev',prev); icon.className= ok ? 'fa-duotone fa-clipboard-check':'fa-duotone fa-circle-exclamation'; setTimeout(()=>{ icon.className=prev; },1800); }
function handleShareClick(e){ e.preventDefault(); const btn=e.currentTarget; const id=btn.getAttribute('data-share-target'); if(id) openModal(id); }
function bindShareButtons(){
document.querySelectorAll('.h-share').forEach(btn=>{
if(!btn.dataset.hShareBound){ btn.addEventListener('click', handleShareClick); btn.dataset.hShareBound='1'; }
});
}
bindShareButtons();
if(document.readyState==='loading'){
document.addEventListener('DOMContentLoaded', bindShareButtons);
} else {
requestAnimationFrame(bindShareButtons);
}
document.addEventListener('click', function(e){
const shareBtn=e.target.closest && e.target.closest('.h-share');
if(shareBtn && !shareBtn.dataset.hShareBound){ handleShareClick.call(shareBtn, e); }
}, true);
document.addEventListener('click', e=>{
if(e.target===modal) closeModal();
if(e.target.closest && e.target.closest('.hsm-close')){ e.preventDefault(); closeModal(); }
if(copyBtn && (e.target===copyBtn || (e.target.closest && e.target.closest('.hsm-copy')))) { e.preventDefault(); copyCurrent(); }
});
document.addEventListener('keydown', e=>{ if(e.key==='Escape' && isOpen()) closeModal(); });
function trapFocus(){
if(trapBound) return;
trapBound=true;
modal.addEventListener('keydown', f=>{ if(f.key==='Tab' && isOpen()){ const focusable=[...modal.querySelectorAll('a[href],button,input,textarea,select,[tabindex]:not([tabindex="-1"])')].filter(el=>!el.hasAttribute('disabled')); if(!focusable.length) return; const first=focusable[0]; const last=focusable[focusable.length-1]; if(f.shiftKey && document.activeElement===first){ f.preventDefault(); last.focus(); } else if(!f.shiftKey && document.activeElement===last){ f.preventDefault(); first.focus(); } } });
}
if(closeBtn) closeBtn.addEventListener('click', e=>{ e.preventDefault(); closeModal(); });
})();
</script><p>Learn how to optimize query performance in Geode through strategic index design, EXPLAIN analysis, and performance tuning. This tutorial covers B-tree, HNSW vector, spatial, and full-text indexes with practical examples.</p>
<h3 id="prerequisites" class="position-relative d-flex align-items-center group">
<span>Prerequisites</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="prerequisites"
aria-haspopup="dialog"
aria-label="Share link: Prerequisites">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3><ul>
<li>Geode server running (port 3141)</li>
<li>Basic GQL knowledge</li>
<li>Sample dataset loaded (we’ll create one)</li>
<li>Understanding of query patterns</li>
</ul>
<h3 id="learning-objectives" class="position-relative d-flex align-items-center group">
<span>Learning Objectives</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="learning-objectives"
aria-haspopup="dialog"
aria-label="Share link: Learning Objectives">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3><p>By completing this tutorial, you will:</p>
<ol>
<li>Understand different index types and their use cases</li>
<li>Use EXPLAIN to analyze query execution plans</li>
<li>Create and optimize B-tree indexes</li>
<li>Implement HNSW vector indexes for similarity search</li>
<li>Configure full-text search with BM25 ranking</li>
<li>Monitor index performance and effectiveness</li>
</ol>
<h3 id="tutorial-dataset" class="position-relative d-flex align-items-center group">
<span>Tutorial Dataset</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="tutorial-dataset"
aria-haspopup="dialog"
aria-label="Share link: Tutorial Dataset">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3><p>Let’s create a realistic e-commerce dataset:</p>
<p>```gql
– Create customers
CREATE (c1:Customer {
id: 1,
name: ‘Alice Johnson’,
email: ‘<a
href="mailto:[email protected]"
>[email protected]</a>
’,
location: point({latitude: 37.7749, longitude: -122.4194}),
joined: datetime(‘2023-01-15T10:30:00’)
})</p>
<p>CREATE (c2:Customer {
id: 2,
name: ‘Bob Smith’,
email: ‘<a
href="mailto:[email protected]"
>[email protected]</a>
’,
location: point({latitude: 40.7128, longitude: -74.0060}),
joined: datetime(‘2023-02-20T14:15:00’)
})</p>
<p>CREATE (c3:Customer {
id: 3,
name: ‘Charlie Brown’,
email: ‘<a
href="mailto:[email protected]"
>[email protected]</a>
’,
location: point({latitude: 34.0522, longitude: -118.2437}),
joined: datetime(‘2023-03-10T09:45:00’)
})</p>
<p>– Create products
CREATE (p1:Product {
id: 101,
name: ‘Wireless Headphones’,
description: ‘Premium wireless headphones with noise cancellation and 30-hour battery life’,
price: 199.99,
category: ‘Electronics’,
stock: 150,
embedding: [0.1, 0.3, 0.5, 0.2, 0.8, 0.4, 0.6, 0.7]
})</p>
<p>CREATE (p2:Product {
id: 102,
name: ‘Smartphone Case’,
description: ‘Durable protective case for smartphones with shock absorption’,
price: 29.99,
category: ‘Accessories’,
stock: 500,
embedding: [0.2, 0.4, 0.1, 0.9, 0.3, 0.5, 0.2, 0.6]
})</p>
<p>CREATE (p3:Product {
id: 103,
name: ‘USB-C Cable’,
description: ‘Fast charging USB-C cable with data transfer support’,
price: 15.99,
category: ‘Accessories’,
stock: 1000,
embedding: [0.3, 0.2, 0.7, 0.1, 0.4, 0.8, 0.3, 0.5]
})</p>
<p>– Create orders and relationships
MATCH (c:Customer {id: 1}), (p:Product {id: 101})
CREATE (c)-[:PURCHASED {date: datetime(‘2023-04-01T10:00:00’), quantity: 1}]->(p)</p>
<p>MATCH (c:Customer {id: 1}), (p:Product {id: 102})
CREATE (c)-[:PURCHASED {date: datetime(‘2023-04-01T10:05:00’), quantity: 2}]->(p)</p>
<p>MATCH (c:Customer {id: 2}), (p:Product {id: 103})
CREATE (c)-[:PURCHASED {date: datetime(‘2023-04-05T15:30:00’), quantity: 5}]->(p)</p>
<p>– Create product views
MATCH (c:Customer {id: 3}), (p:Product {id: 101})
CREATE (c)-[:VIEWED {timestamp: datetime(‘2023-04-10T08:20:00’)}]->(p)
```</p>
<h3 id="part-1-understanding-query-plans-with-explain" class="position-relative d-flex align-items-center group">
<span>Part 1: Understanding Query Plans with EXPLAIN</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="part-1-understanding-query-plans-with-explain"
aria-haspopup="dialog"
aria-label="Share link: Part 1: Understanding Query Plans with EXPLAIN">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="step-1-baseline-query-analysis" class="position-relative d-flex align-items-center group">
<span>Step 1: Baseline Query Analysis</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="step-1-baseline-query-analysis"
aria-haspopup="dialog"
aria-label="Share link: Step 1: Baseline Query Analysis">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Let’s analyze a simple query without indexes:</p>
<p>```gql
EXPLAIN MATCH (c:Customer {email: ‘<a
href="mailto:[email protected]"
>[email protected]</a>
’}) RETURN c
```</p>
<p><strong>Expected Output</strong>:
```</p>
<table>
<thead>
<tr>
<th>plan</th>
</tr>
</thead>
<tbody>
<tr>
<td>EXPLAIN</td>
</tr>
<tr>
<td>MATCH</td>
</tr>
<tr>
<td>NodeScan</td>
</tr>
<tr>
<td>Filter</td>
</tr>
<tr>
<td>RETURN</td>
</tr>
<tr>
<td>Project</td>
</tr>
<tr>
<td>```</td>
</tr>
</tbody>
</table>
<p><strong>Analysis</strong>:</p>
<ul>
<li><strong>NodeScan</strong>: Scans all Customer nodes (O(n) complexity)</li>
<li><strong>Filter</strong>: Applies email predicate after scan</li>
<li><strong>Problem</strong>: Inefficient for large datasets</li>
</ul>
<h4 id="step-2-create-b-tree-index" class="position-relative d-flex align-items-center group">
<span>Step 2: Create B-tree Index</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="step-2-create-b-tree-index"
aria-haspopup="dialog"
aria-label="Share link: Step 2: Create B-tree Index">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Create an index on the email field:</p>
<p>```gql
CREATE INDEX ON :Customer(email)
```</p>
<p>Now re-run the EXPLAIN:</p>
<p>```gql
EXPLAIN MATCH (c:Customer {email: ‘<a
href="mailto:[email protected]"
>[email protected]</a>
’}) RETURN c
```</p>
<p><strong>Improved Output</strong>:
```</p>
<table>
<thead>
<tr>
<th>plan</th>
</tr>
</thead>
<tbody>
<tr>
<td>EXPLAIN</td>
</tr>
<tr>
<td>MATCH</td>
</tr>
<tr>
<td>IndexSeek</td>
</tr>
<tr>
<td>RETURN</td>
</tr>
<tr>
<td>Project</td>
</tr>
<tr>
<td>```</td>
</tr>
</tbody>
</table>
<p><strong>Analysis</strong>:</p>
<ul>
<li><strong>IndexSeek</strong>: Uses B-tree index for O(log n) lookup</li>
<li><strong>No Filter</strong>: Predicate handled by index</li>
<li><strong>Benefit</strong>: Significantly faster for large datasets</li>
</ul>
<h4 id="step-3-profile-query-performance" class="position-relative d-flex align-items-center group">
<span>Step 3: Profile Query Performance</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="step-3-profile-query-performance"
aria-haspopup="dialog"
aria-label="Share link: Step 3: Profile Query Performance">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Use PROFILE to measure actual execution:</p>
<p>```gql
PROFILE MATCH (c:Customer {email: ‘<a
href="mailto:[email protected]"
>[email protected]</a>
’}) RETURN c
```</p>
<p><strong>Output</strong>:
```</p>
<table>
<thead>
<tr>
<th>metric</th>
<th>value</th>
</tr>
</thead>
<tbody>
<tr>
<td>rows_returned</td>
<td>1</td>
</tr>
<tr>
<td>columns</td>
<td>1</td>
</tr>
<tr>
<td>execution_time_ms</td>
<td>1</td>
</tr>
<tr>
<td>```</td>
<td></td>
</tr>
</tbody>
</table>
<p><strong>Interpretation</strong>:</p>
<ul>
<li>Query completes in ~1ms with index</li>
<li>Without index: ~50-100ms for 100k customers</li>
</ul>
<h3 id="part-2-b-tree-index-optimization" class="position-relative d-flex align-items-center group">
<span>Part 2: B-tree Index Optimization</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="part-2-b-tree-index-optimization"
aria-haspopup="dialog"
aria-label="Share link: Part 2: B-tree Index Optimization">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="composite-indexes" class="position-relative d-flex align-items-center group">
<span>Composite Indexes</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="composite-indexes"
aria-haspopup="dialog"
aria-label="Share link: Composite Indexes">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Create a composite index for complex queries:</p>
<p>```gql
– Create composite index
CREATE INDEX ON :Product(category, price)</p>
<p>– Query using composite index
EXPLAIN MATCH (p:Product)
WHERE p.category = ‘Electronics’ AND p.price < 300
RETURN p.name, p.price
ORDER BY p.price
```</p>
<p><strong>Plan Analysis</strong>:
```</p>
<table>
<thead>
<tr>
<th>plan</th>
</tr>
</thead>
<tbody>
<tr>
<td>EXPLAIN</td>
</tr>
<tr>
<td>MATCH</td>
</tr>
<tr>
<td>IndexSeek</td>
</tr>
<tr>
<td>RETURN</td>
</tr>
<tr>
<td>Project</td>
</tr>
<tr>
<td>Sort</td>
</tr>
<tr>
<td>```</td>
</tr>
</tbody>
</table>
<p><strong>Benefits</strong>:</p>
<ul>
<li>Index handles both WHERE predicates</li>
<li>ORDER BY can use index ordering</li>
<li>No separate sort operation needed</li>
</ul>
<h4 id="index-selection-guidelines" class="position-relative d-flex align-items-center group">
<span>Index Selection Guidelines</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="index-selection-guidelines"
aria-haspopup="dialog"
aria-label="Share link: Index Selection Guidelines">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>When to Use B-tree Indexes</strong>:</p>
<ol>
<li>
<p><strong>Equality Lookups</strong>:
```gql
– Excellent for B-tree
MATCH (c:Customer {email: $email}) RETURN c
MATCH (p:Product {id: $id}) RETURN p
```</p>
</li>
<li>
<p><strong>Range Queries</strong>:
```gql
– Excellent for B-tree
MATCH (p:Product)
WHERE p.price >= 50 AND p.price <= 200
RETURN p
```</p>
</li>
<li>
<p><strong>Prefix Matching</strong>:
```gql
– Good for B-tree
MATCH (c:Customer)
WHERE c.name STARTS WITH ‘Alice’
RETURN c
```</p>
</li>
<li>
<p><strong>Sorting</strong>:
```gql
– B-tree index provides sorted access
MATCH (p:Product)
WHERE p.category = ‘Electronics’
RETURN p.name
ORDER BY p.price – Uses index ordering
```</p>
</li>
</ol>
<p><strong>When NOT to Use B-tree Indexes</strong>:</p>
<ol>
<li>
<p><strong>Low Cardinality Fields</strong>:
```gql
– Don’t index boolean or low-cardinality fields
CREATE INDEX ON :Product(in_stock) – Only true/false values
```</p>
</li>
<li>
<p><strong>Frequently Updated Fields</strong>:</p>
</li>
</ol>
<ul>
<li>Index maintenance overhead on writes</li>
<li>Consider read/write ratio</li>
</ul>
<ol start="3">
<li><strong>Large Text Fields</strong>:</li>
</ol>
<ul>
<li>Use full-text indexes instead</li>
</ul>
<h3 id="part-3-hnsw-vector-index-for-similarity-search" class="position-relative d-flex align-items-center group">
<span>Part 3: HNSW Vector Index for Similarity Search</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="part-3-hnsw-vector-index-for-similarity-search"
aria-haspopup="dialog"
aria-label="Share link: Part 3: HNSW Vector Index for Similarity Search">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="step-1-create-hnsw-index" class="position-relative d-flex align-items-center group">
<span>Step 1: Create HNSW Index</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="step-1-create-hnsw-index"
aria-haspopup="dialog"
aria-label="Share link: Step 1: Create HNSW Index">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Create a vector index for product embeddings:</p>
<p>```gql
CREATE VECTOR INDEX product_embeddings
ON :Product(embedding)
OPTIONS {
dimensions: 8,
distance: ‘cosine’,
ef_construction: 200,
m: 16
}
```</p>
<p><strong>Index Parameters</strong>:</p>
<ul>
<li><strong>dimensions</strong>: Vector dimensionality (8 in our example)</li>
<li><strong>distance</strong>: Distance metric (cosine, euclidean, manhattan, dot_product)</li>
<li><strong>ef_construction</strong>: Build-time quality (higher = better quality, slower build)</li>
<li><strong>m</strong>: Max connections per node (higher = better recall, more memory)</li>
</ul>
<h4 id="step-2-similarity-search-query" class="position-relative d-flex align-items-center group">
<span>Step 2: Similarity Search Query</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="step-2-similarity-search-query"
aria-haspopup="dialog"
aria-label="Share link: Step 2: Similarity Search Query">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Find products similar to a query vector:</p>
<p>```gql
MATCH (p:Product)
WHERE vector_similarity(p.embedding, [0.15, 0.35, 0.45, 0.25, 0.75, 0.45, 0.55, 0.65], ‘cosine’) > 0.8
RETURN p.name, p.description
ORDER BY vector_similarity(p.embedding, [0.15, 0.35, 0.45, 0.25, 0.75, 0.45, 0.55, 0.65], ‘cosine’) DESC
LIMIT 5
```</p>
<h4 id="step-3-optimize-hnsw-parameters" class="position-relative d-flex align-items-center group">
<span>Step 3: Optimize HNSW Parameters</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="step-3-optimize-hnsw-parameters"
aria-haspopup="dialog"
aria-label="Share link: Step 3: Optimize HNSW Parameters">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>For High Recall (Recommendation Systems)</strong>:
```gql
CREATE VECTOR INDEX product_embeddings_high_recall
ON :Product(embedding)
OPTIONS {
dimensions: 8,
distance: ‘cosine’,
ef_construction: 400, – Higher for better quality
m: 32, – More connections
ef_search: 200 – Search-time parameter
}
```</p>
<p><strong>For Low Latency (Real-time Search)</strong>:
```gql
CREATE VECTOR INDEX product_embeddings_fast
ON :Product(embedding)
OPTIONS {
dimensions: 8,
distance: ’euclidean’,
ef_construction: 100, – Lower for faster build
m: 8, – Fewer connections
ef_search: 50 – Faster search
}
```</p>
<p><strong>Performance Trade-offs</strong>:</p>
<table>
<thead>
<tr>
<th>Parameter</th>
<th>Higher Value</th>
<th>Lower Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>ef_construction</td>
<td>Better recall, slower build</td>
<td>Faster build, lower recall</td>
</tr>
<tr>
<td>m</td>
<td>Better recall, more memory</td>
<td>Less memory, lower recall</td>
</tr>
<tr>
<td>ef_search</td>
<td>Better recall, slower query</td>
<td>Faster query, lower recall</td>
</tr>
</tbody>
</table>
<h4 id="step-4-distance-metric-selection" class="position-relative d-flex align-items-center group">
<span>Step 4: Distance Metric Selection</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="step-4-distance-metric-selection"
aria-haspopup="dialog"
aria-label="Share link: Step 4: Distance Metric Selection">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>Cosine Similarity</strong> - Recommended for normalized embeddings:
```gql
– Good for text embeddings, ML features
distance: ‘cosine’
```</p>
<p><strong>Euclidean Distance</strong> - For absolute magnitude:
```gql
– Good for spatial data, image features
distance: ’euclidean’
```</p>
<p><strong>Dot Product</strong> - For unnormalized vectors:
```gql
– Good for recommendation scores
distance: ‘dot_product’
```</p>
<p><strong>Manhattan Distance</strong> - For sparse vectors:
```gql
– Good for high-dimensional sparse data
distance: ‘manhattan’
```</p>
<h3 id="part-4-full-text-search-with-bm25" class="position-relative d-flex align-items-center group">
<span>Part 4: Full-Text Search with BM25</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="part-4-full-text-search-with-bm25"
aria-haspopup="dialog"
aria-label="Share link: Part 4: Full-Text Search with BM25">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="step-1-create-full-text-index" class="position-relative d-flex align-items-center group">
<span>Step 1: Create Full-Text Index</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="step-1-create-full-text-index"
aria-haspopup="dialog"
aria-label="Share link: Step 1: Create Full-Text Index">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Create a full-text index on product descriptions:</p>
<p>```gql
CREATE FULLTEXT INDEX product_search
ON :Product(name, description)
OPTIONS {
analyzer: ‘standard’,
k1: 1.2,
b: 0.75
}
```</p>
<p><strong>BM25 Parameters</strong>:</p>
<ul>
<li><strong>k1</strong>: Term frequency saturation (typical: 1.2-2.0)</li>
<li><strong>b</strong>: Length normalization (0.0 = no normalization, 1.0 = full normalization)</li>
<li><strong>analyzer</strong>: Text tokenization (standard, english, whitespace)</li>
</ul>
<h4 id="step-2-full-text-search-query" class="position-relative d-flex align-items-center group">
<span>Step 2: Full-Text Search Query</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="step-2-full-text-search-query"
aria-haspopup="dialog"
aria-label="Share link: Step 2: Full-Text Search Query">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Search for products mentioning “wireless charging”:</p>
<p>```gql
MATCH (p:Product)
WHERE fulltext_search(p, ‘wireless charging’)
RETURN p.name, p.description, fulltext_score(p, ‘wireless charging’) AS score
ORDER BY score DESC
LIMIT 10
```</p>
<h4 id="step-3-optimize-bm25-parameters" class="position-relative d-flex align-items-center group">
<span>Step 3: Optimize BM25 Parameters</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="step-3-optimize-bm25-parameters"
aria-haspopup="dialog"
aria-label="Share link: Step 3: Optimize BM25 Parameters">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>For Short Documents</strong> (product names):
```gql
CREATE FULLTEXT INDEX product_names
ON :Product(name)
OPTIONS {
k1: 2.0, – Higher for short documents
b: 0.5 – Less length normalization
}
```</p>
<p><strong>For Long Documents</strong> (descriptions, reviews):
```gql
CREATE FULLTEXT INDEX product_descriptions
ON :Product(description)
OPTIONS {
k1: 1.2, – Standard value
b: 0.75 – Standard length normalization
}
```</p>
<p><strong>For Exact Phrase Matching</strong>:
```gql
MATCH (p:Product)
WHERE fulltext_search(p, ‘“noise cancellation”’) – Exact phrase
RETURN p.name, p.description
```</p>
<h4 id="step-4-multi-field-search" class="position-relative d-flex align-items-center group">
<span>Step 4: Multi-field Search</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="step-4-multi-field-search"
aria-haspopup="dialog"
aria-label="Share link: Step 4: Multi-field Search">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Search across multiple fields with weights:</p>
<p>```gql
MATCH (p:Product)
WHERE fulltext_search(p.name, ‘headphones’, {boost: 2.0})
OR fulltext_search(p.description, ‘headphones’, {boost: 1.0})
RETURN p.name,
fulltext_score(p.name, ‘headphones’) * 2.0 +
fulltext_score(p.description, ‘headphones’) AS total_score
ORDER BY total_score DESC
LIMIT 10
```</p>
<h3 id="part-5-spatial-indexes-for-geographic-queries" class="position-relative d-flex align-items-center group">
<span>Part 5: Spatial Indexes for Geographic Queries</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="part-5-spatial-indexes-for-geographic-queries"
aria-haspopup="dialog"
aria-label="Share link: Part 5: Spatial Indexes for Geographic Queries">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="step-1-create-spatial-index" class="position-relative d-flex align-items-center group">
<span>Step 1: Create Spatial Index</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="step-1-create-spatial-index"
aria-haspopup="dialog"
aria-label="Share link: Step 1: Create Spatial Index">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Create an R-tree spatial index for customer locations:</p>
<p>```gql
CREATE SPATIAL INDEX customer_locations
ON :Customer(location)
OPTIONS {
dimensions: 2,
min_entries: 4,
max_entries: 16
}
```</p>
<h4 id="step-2-geographic-range-query" class="position-relative d-flex align-items-center group">
<span>Step 2: Geographic Range Query</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="step-2-geographic-range-query"
aria-haspopup="dialog"
aria-label="Share link: Step 2: Geographic Range Query">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Find customers within 50km of a point:</p>
<p>```gql
MATCH (c:Customer)
WHERE distance(c.location, point({latitude: 37.7749, longitude: -122.4194})) < 50000 – meters
RETURN c.name, c.location,
distance(c.location, point({latitude: 37.7749, longitude: -122.4194})) / 1000 AS distance_km
ORDER BY distance_km
```</p>
<h4 id="step-3-bounding-box-query" class="position-relative d-flex align-items-center group">
<span>Step 3: Bounding Box Query</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="step-3-bounding-box-query"
aria-haspopup="dialog"
aria-label="Share link: Step 3: Bounding Box Query">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Find customers in a geographic bounding box:</p>
<p>```gql
MATCH (c:Customer)
WHERE c.location.latitude >= 37.0 AND c.location.latitude <= 38.0
AND c.location.longitude >= -123.0 AND c.location.longitude <= -121.0
RETURN c.name, c.location
```</p>
<h3 id="part-6-index-maintenance-and-monitoring" class="position-relative d-flex align-items-center group">
<span>Part 6: Index Maintenance and Monitoring</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="part-6-index-maintenance-and-monitoring"
aria-haspopup="dialog"
aria-label="Share link: Part 6: Index Maintenance and Monitoring">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="step-1-list-all-indexes" class="position-relative d-flex align-items-center group">
<span>Step 1: List All Indexes</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="step-1-list-all-indexes"
aria-haspopup="dialog"
aria-label="Share link: Step 1: List All Indexes">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>```gql
CALL db.indexes() YIELD name, type, properties, options
RETURN name, type, properties, options
```</p>
<p><strong>Output</strong>:
```</p>
<table>
<thead>
<tr>
<th>name</th>
<th>type</th>
<th>properties</th>
<th>options</th>
</tr>
</thead>
<tbody>
<tr>
<td>customer_email</td>
<td>btree</td>
<td>[“email”]</td>
<td>{}</td>
</tr>
<tr>
<td>product_category_price</td>
<td>btree</td>
<td>[“category”,“price”]</td>
<td>{}</td>
</tr>
<tr>
<td>product_embeddings</td>
<td>hnsw</td>
<td>[“embedding”]</td>
<td>{dimensions:8,…}</td>
</tr>
<tr>
<td>product_search</td>
<td>fulltext</td>
<td>[“name”,“description”]</td>
<td>{k1:1.2,b:0.75}</td>
</tr>
<tr>
<td>customer_locations</td>
<td>spatial</td>
<td>[“location”]</td>
<td>{dimensions:2}</td>
</tr>
<tr>
<td>```</td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<h4 id="step-2-analyze-index-usage" class="position-relative d-flex align-items-center group">
<span>Step 2: Analyze Index Usage</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="step-2-analyze-index-usage"
aria-haspopup="dialog"
aria-label="Share link: Step 2: Analyze Index Usage">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Check which indexes are being used:</p>
<p>```gql
CALL db.index.stats() YIELD name, hits, misses, hit_rate
WHERE hit_rate < 0.5 – Find underutilized indexes
RETURN name, hits, misses, hit_rate
ORDER BY hit_rate
```</p>
<h4 id="step-3-rebuild-index" class="position-relative d-flex align-items-center group">
<span>Step 3: Rebuild Index</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="step-3-rebuild-index"
aria-haspopup="dialog"
aria-label="Share link: Step 3: Rebuild Index">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Rebuild an index to improve performance:</p>
<p>```gql
– Drop and recreate index
DROP INDEX customer_email</p>
<p>CREATE INDEX ON :Customer(email)
```</p>
<h4 id="step-4-monitor-index-size" class="position-relative d-flex align-items-center group">
<span>Step 4: Monitor Index Size</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="step-4-monitor-index-size"
aria-haspopup="dialog"
aria-label="Share link: Step 4: Monitor Index Size">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Check index storage size:</p>
<p>```gql
CALL db.index.size() YIELD name, size_bytes, entry_count
RETURN name, size_bytes / (1024 * 1024) AS size_mb, entry_count
ORDER BY size_mb DESC
```</p>
<h3 id="part-7-advanced-optimization-techniques" class="position-relative d-flex align-items-center group">
<span>Part 7: Advanced Optimization Techniques</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="part-7-advanced-optimization-techniques"
aria-haspopup="dialog"
aria-label="Share link: Part 7: Advanced Optimization Techniques">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="covering-indexes" class="position-relative d-flex align-items-center group">
<span>Covering Indexes</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="covering-indexes"
aria-haspopup="dialog"
aria-label="Share link: Covering Indexes">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Create indexes that include all queried fields:</p>
<p>```gql
– Create covering index
CREATE INDEX ON :Product(category, name, price)</p>
<p>– Query covered by index (no table lookup needed)
MATCH (p:Product)
WHERE p.category = ‘Electronics’
RETURN p.name, p.price – All fields in index
```</p>
<h4 id="index-hints" class="position-relative d-flex align-items-center group">
<span>Index Hints</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="index-hints"
aria-haspopup="dialog"
aria-label="Share link: Index Hints">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Force query planner to use specific index:</p>
<p>```gql
– Use index hint
MATCH (p:Product)
USING INDEX product_category_price
WHERE p.category = ‘Electronics’ AND p.price < 300
RETURN p
```</p>
<h4 id="partial-indexes" class="position-relative d-flex align-items-center group">
<span>Partial Indexes</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="partial-indexes"
aria-haspopup="dialog"
aria-label="Share link: Partial Indexes">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Create indexes with filter conditions (if supported):</p>
<p>```gql
– Index only active products
CREATE INDEX ON :Product(name)
WHERE in_stock = true
```</p>
<h4 id="index-only-scans" class="position-relative d-flex align-items-center group">
<span>Index-Only Scans</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="index-only-scans"
aria-haspopup="dialog"
aria-label="Share link: Index-Only Scans">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Optimize queries to use index-only scans:</p>
<p>```gql
– Before: Requires table access
MATCH (p:Product)
WHERE p.category = ‘Electronics’
RETURN p – Returns all properties</p>
<p>– After: Index-only scan
MATCH (p:Product)
WHERE p.category = ‘Electronics’
RETURN p.name, p.category – Only indexed properties
```</p>
<h3 id="part-8-performance-testing" class="position-relative d-flex align-items-center group">
<span>Part 8: Performance Testing</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="part-8-performance-testing"
aria-haspopup="dialog"
aria-label="Share link: Part 8: Performance Testing">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="step-1-benchmark-query-performance" class="position-relative d-flex align-items-center group">
<span>Step 1: Benchmark Query Performance</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="step-1-benchmark-query-performance"
aria-haspopup="dialog"
aria-label="Share link: Step 1: Benchmark Query Performance">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Create a benchmark dataset:</p>
<p>```bash</p>
<h2 id="generate-100k-customers" class="position-relative d-flex align-items-center group">
<span>Generate 100k customers</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="generate-100k-customers"
aria-haspopup="dialog"
aria-label="Share link: Generate 100k customers">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h2><p>for i in {1..100000}; do
echo “CREATE (:Customer {
id: $i,
email: ‘<a
href="mailto:user$%7bi%[email protected]"
>user${i}@example.com</a>
’,
name: ‘User $i’
})”
done | geode query
```</p>
<h4 id="step-2-measure-query-performance" class="position-relative d-flex align-items-center group">
<span>Step 2: Measure Query Performance</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="step-2-measure-query-performance"
aria-haspopup="dialog"
aria-label="Share link: Step 2: Measure Query Performance">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>Without Index</strong>:
```gql
– Measure time
PROFILE MATCH (c:Customer {email: ‘<a
href="mailto:[email protected]"
>[email protected]</a>
’}) RETURN c
– execution_time_ms: ~150ms (full scan)
```</p>
<p><strong>With Index</strong>:
```gql
CREATE INDEX ON :Customer(email)</p>
<p>PROFILE MATCH (c:Customer {email: ‘<a
href="mailto:[email protected]"
>[email protected]</a>
’}) RETURN c
– execution_time_ms: ~2ms (index seek)
```</p>
<p><strong>Performance Improvement</strong>: 75x faster</p>
<h4 id="step-3-load-testing" class="position-relative d-flex align-items-center group">
<span>Step 3: Load Testing</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="step-3-load-testing"
aria-haspopup="dialog"
aria-label="Share link: Step 3: Load Testing">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Use a load testing tool to measure throughput:</p>
<p>```python
import asyncio
from geode_client import open_database
import time</p>
<p>async def benchmark_queries(db, num_queries=1000):
start = time.time()
tasks = []</p>
<pre><code>async with db.connection() as conn:
for i in range(num_queries):
task = conn.query(
"MATCH (c:Customer {email: $email}) RETURN c",
{"email": f"user{i}@example.com"}
)
tasks.append(task)
await asyncio.gather(*tasks)
elapsed = time.time() - start
qps = num_queries / elapsed
print(f"Queries: {num_queries}, Time: {elapsed:.2f}s, QPS: {qps:.0f}")
</code></pre>
<h2 id="run-benchmark" class="position-relative d-flex align-items-center group">
<span>Run benchmark</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="run-benchmark"
aria-haspopup="dialog"
aria-label="Share link: Run benchmark">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h2><p>db = open_database(“quic://localhost:3141”, pool_size=50)
asyncio.run(benchmark_queries(db, 1000))</p>
<h2 id="output-queries-1000-time-215s-qps-465" class="position-relative d-flex align-items-center group">
<span>Output: Queries: 1000, Time: 2.15s, QPS: 465</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="output-queries-1000-time-215s-qps-465"
aria-haspopup="dialog"
aria-label="Share link: Output: Queries: 1000, Time: 2.15s, QPS: 465">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h2><p>```</p>
<h3 id="part-9-common-pitfalls-and-solutions" class="position-relative d-flex align-items-center group">
<span>Part 9: Common Pitfalls and Solutions</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="part-9-common-pitfalls-and-solutions"
aria-haspopup="dialog"
aria-label="Share link: Part 9: Common Pitfalls and Solutions">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="pitfall-1-too-many-indexes" class="position-relative d-flex align-items-center group">
<span>Pitfall 1: Too Many Indexes</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="pitfall-1-too-many-indexes"
aria-haspopup="dialog"
aria-label="Share link: Pitfall 1: Too Many Indexes">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>Problem</strong>: Every index adds write overhead</p>
<p><strong>Solution</strong>: Only create indexes for frequent queries
```gql
– Analyze query patterns first
CALL db.query.stats() YIELD query, execution_count
WHERE execution_count > 100
RETURN query, execution_count
ORDER BY execution_count DESC
LIMIT 10</p>
<p>– Create indexes for top queries only
```</p>
<h4 id="pitfall-2-wrong-index-type" class="position-relative d-flex align-items-center group">
<span>Pitfall 2: Wrong Index Type</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="pitfall-2-wrong-index-type"
aria-haspopup="dialog"
aria-label="Share link: Pitfall 2: Wrong Index Type">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>Problem</strong>: B-tree index for vector similarity</p>
<p><strong>Solution</strong>: Use appropriate index type
```gql
– Wrong: B-tree for embeddings
CREATE INDEX ON :Product(embedding)</p>
<p>– Correct: HNSW for embeddings
CREATE VECTOR INDEX ON :Product(embedding)
OPTIONS {dimensions: 8, distance: ‘cosine’}
```</p>
<h4 id="pitfall-3-unselective-indexes" class="position-relative d-flex align-items-center group">
<span>Pitfall 3: Unselective Indexes</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="pitfall-3-unselective-indexes"
aria-haspopup="dialog"
aria-label="Share link: Pitfall 3: Unselective Indexes">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>Problem</strong>: Index on low-cardinality field</p>
<p><strong>Solution</strong>: Check index selectivity
```gql
– Check cardinality
MATCH (p:Product)
RETURN p.category, count(*) AS count
ORDER BY count DESC</p>
<p>– If most values have high count, index is not useful
```</p>
<h4 id="pitfall-4-stale-statistics" class="position-relative d-flex align-items-center group">
<span>Pitfall 4: Stale Statistics</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="pitfall-4-stale-statistics"
aria-haspopup="dialog"
aria-label="Share link: Pitfall 4: Stale Statistics">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>Problem</strong>: Query planner uses outdated statistics</p>
<p><strong>Solution</strong>: Update statistics regularly
```gql
CALL db.stats.update()
```</p>
<h3 id="practice-exercises" class="position-relative d-flex align-items-center group">
<span>Practice Exercises</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="practice-exercises"
aria-haspopup="dialog"
aria-label="Share link: Practice Exercises">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="exercise-1-e-commerce-search-optimization" class="position-relative d-flex align-items-center group">
<span>Exercise 1: E-commerce Search Optimization</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="exercise-1-e-commerce-search-optimization"
aria-haspopup="dialog"
aria-label="Share link: Exercise 1: E-commerce Search Optimization">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>Task</strong>: Optimize this query:
```gql
MATCH (p:Product)
WHERE p.category = ‘Electronics’
AND p.price >= 100 AND p.price <= 500
AND fulltext_search(p.description, ‘wireless bluetooth’)
RETURN p.name, p.price, fulltext_score(p.description, ‘wireless bluetooth’) AS score
ORDER BY score DESC, p.price
LIMIT 20
```</p>
<p><strong>Steps</strong>:</p>
<ol>
<li>Create composite B-tree index: category + price</li>
<li>Create full-text index on description</li>
<li>Verify with EXPLAIN</li>
<li>Measure with PROFILE</li>
</ol>
<p><strong>Solution</strong>:
```gql
CREATE INDEX ON :Product(category, price)
CREATE FULLTEXT INDEX ON :Product(description)</p>
<p>EXPLAIN MATCH (p:Product)
WHERE p.category = ‘Electronics’
AND p.price >= 100 AND p.price <= 500
AND fulltext_search(p.description, ‘wireless bluetooth’)
RETURN p.name, p.price, fulltext_score(p.description, ‘wireless bluetooth’) AS score
ORDER BY score DESC, p.price
LIMIT 20
```</p>
<h4 id="exercise-2-geospatial-query-optimization" class="position-relative d-flex align-items-center group">
<span>Exercise 2: Geospatial Query Optimization</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="exercise-2-geospatial-query-optimization"
aria-haspopup="dialog"
aria-label="Share link: Exercise 2: Geospatial Query Optimization">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>Task</strong>: Find customers within 10km of stores</p>
<p>```gql
MATCH (c:Customer), (s:Store)
WHERE distance(c.location, s.location) < 10000
RETURN c.name, s.name, distance(c.location, s.location) AS distance_m
ORDER BY distance_m
```</p>
<p><strong>Steps</strong>:</p>
<ol>
<li>Create spatial indexes on both Customer and Store locations</li>
<li>Use EXPLAIN to verify R-tree usage</li>
<li>Compare performance with/without indexes</li>
</ol>
<p><strong>Solution</strong>:
```gql
CREATE SPATIAL INDEX ON :Customer(location)
CREATE SPATIAL INDEX ON :Store(location)</p>
<p>PROFILE MATCH (c:Customer), (s:Store)
WHERE distance(c.location, s.location) < 10000
RETURN c.name, s.name, distance(c.location, s.location) AS distance_m
ORDER BY distance_m
```</p>
<h4 id="exercise-3-vector-similarity-optimization" class="position-relative d-flex align-items-center group">
<span>Exercise 3: Vector Similarity Optimization</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="exercise-3-vector-similarity-optimization"
aria-haspopup="dialog"
aria-label="Share link: Exercise 3: Vector Similarity Optimization">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>Task</strong>: Implement product recommendation based on embedding similarity</p>
<p>```gql
– Given a product, find similar products
MATCH (p:Product {id: 101})
MATCH (similar:Product)
WHERE similar.id <> p.id
AND vector_similarity(p.embedding, similar.embedding, ‘cosine’) > 0.7
RETURN similar.name, vector_similarity(p.embedding, similar.embedding, ‘cosine’) AS similarity
ORDER BY similarity DESC
LIMIT 10
```</p>
<p><strong>Steps</strong>:</p>
<ol>
<li>Create HNSW index with optimal parameters</li>
<li>Test different distance metrics</li>
<li>Tune ef_search for recall/latency trade-off</li>
</ol>
<p><strong>Solution</strong>:
```gql
CREATE VECTOR INDEX product_recommendations
ON :Product(embedding)
OPTIONS {
dimensions: 8,
distance: ‘cosine’,
ef_construction: 200,
m: 16,
ef_search: 100
}</p>
<p>– Query uses index automatically
MATCH (p:Product {id: 101})
MATCH (similar:Product)
WHERE similar.id <> p.id
AND vector_similarity(p.embedding, similar.embedding, ‘cosine’) > 0.7
RETURN similar.name, vector_similarity(p.embedding, similar.embedding, ‘cosine’) AS similarity
ORDER BY similarity DESC
LIMIT 10
```</p>
<h3 id="quick-reference-card" class="position-relative d-flex align-items-center group">
<span>Quick Reference Card</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="quick-reference-card"
aria-haspopup="dialog"
aria-label="Share link: Quick Reference Card">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="index-type-selection" class="position-relative d-flex align-items-center group">
<span>Index Type Selection</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="index-type-selection"
aria-haspopup="dialog"
aria-label="Share link: Index Type Selection">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><table>
<thead>
<tr>
<th>Query Pattern</th>
<th>Index Type</th>
<th>Example</th>
</tr>
</thead>
<tbody>
<tr>
<td>Equality lookup</td>
<td>B-tree</td>
<td>`email = ‘<a
href="mailto:[email protected]"
>[email protected]</a>
’`</td>
</tr>
<tr>
<td>Range query</td>
<td>B-tree</td>
<td>`price BETWEEN 100 AND 200`</td>
</tr>
<tr>
<td>Text search</td>
<td>Full-text</td>
<td>`fulltext_search(description, ‘wireless’)`</td>
</tr>
<tr>
<td>Vector similarity</td>
<td>HNSW</td>
<td>`vector_similarity(embedding, query_vector)`</td>
</tr>
<tr>
<td>Geographic range</td>
<td>Spatial</td>
<td>`distance(location, point) < 10000`</td>
</tr>
<tr>
<td>Prefix matching</td>
<td>B-tree</td>
<td>`name STARTS WITH ‘Alice’`</td>
</tr>
</tbody>
</table>
<h4 id="explain-plan-operators" class="position-relative d-flex align-items-center group">
<span>EXPLAIN Plan Operators</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="explain-plan-operators"
aria-haspopup="dialog"
aria-label="Share link: EXPLAIN Plan Operators">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><table>
<thead>
<tr>
<th>Operator</th>
<th>Meaning</th>
<th>Performance</th>
</tr>
</thead>
<tbody>
<tr>
<td>IndexSeek</td>
<td>Index lookup</td>
<td>O(log n) - Excellent</td>
</tr>
<tr>
<td>NodeScan</td>
<td>Full table scan</td>
<td>O(n) - Poor</td>
</tr>
<tr>
<td>Filter</td>
<td>Post-scan filtering</td>
<td>O(n) - Poor if large result set</td>
</tr>
<tr>
<td>VectorIndexScan</td>
<td>HNSW search</td>
<td>O(log n) avg - Good</td>
</tr>
<tr>
<td>SpatialIndexScan</td>
<td>R-tree search</td>
<td>O(log n) - Good</td>
</tr>
</tbody>
</table>
<h4 id="optimization-checklist" class="position-relative d-flex align-items-center group">
<span>Optimization Checklist</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="optimization-checklist"
aria-haspopup="dialog"
aria-label="Share link: Optimization Checklist">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><ul>
<li><input disabled="" type="checkbox"> Analyze query patterns with db.query.stats()</li>
<li><input disabled="" type="checkbox"> Create indexes for frequent queries</li>
<li><input disabled="" type="checkbox"> Use EXPLAIN to verify index usage</li>
<li><input disabled="" type="checkbox"> Use PROFILE to measure performance</li>
<li><input disabled="" type="checkbox"> Monitor index hit rates</li>
<li><input disabled="" type="checkbox"> Update statistics regularly</li>
<li><input disabled="" type="checkbox"> Remove unused indexes</li>
<li><input disabled="" type="checkbox"> Consider covering indexes for common queries</li>
<li><input disabled="" type="checkbox"> Tune HNSW parameters for vector indexes</li>
<li><input disabled="" type="checkbox"> Benchmark before and after index creation</li>
</ul>
<h3 id="next-steps" class="position-relative d-flex align-items-center group">
<span>Next Steps</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="next-steps"
aria-haspopup="dialog"
aria-label="Share link: Next Steps">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3><ol>
<li><strong>Production Deployment</strong> - Apply index strategies to your application</li>
<li><strong>Monitoring</strong> - Set up index usage monitoring</li>
<li><strong>Query Optimization</strong> - Review slow queries and add indexes</li>
<li><strong>Advanced Topics</strong> - Explore query hints and optimizer settings</li>
<li><strong>Performance Testing</strong> - Benchmark with realistic workloads</li>
</ol>
<p><strong>Related Documentation</strong>:</p>
<ul>
<li><a
href="/docs/query/performance-tuning"
>Query Performance Tuning</a>
</li>
<li><a
href="/docs/query/explain-profile"
>EXPLAIN/PROFILE Commands</a>
</li>
<li><a
href="/docs/query/full-text-search"
>Full-Text Search</a>
</li>
<li><a
href="/docs/query/indexing-and-optimization/"
>Indexing Reference</a>
</li>
</ul>
<hr>
<p><em>Last Updated: January 2026</em>
<em>Difficulty: Intermediate</em>
<em>Estimated Time: 90 minutes</em></p>
Index Optimization Tutorial
Practical guide to index optimization in Geode including EXPLAIN analysis, B-tree, HNSW, and full-text indexes with performance tuning strategies