Skip to main content
The Quran Search Engine uses a multi-layered architecture that combines simple text matching, linguistic analysis, and fuzzy search to deliver accurate and relevant results.

Search layers

The search engine processes queries through three distinct layers, each providing progressively more sophisticated matching:

1. Simple search layer

The first layer performs direct text matching using normalized Arabic.
Simple search uses AND logic: all query tokens must be present in the verse for a match.
Key features:
  • Normalizes both query and verse text using normalizeArabic()
  • Strips non-Arabic characters from the query
  • Splits query into tokens by whitespace
  • Returns verses where every token appears in the text

2. Linguistic search layer

The second layer uses morphological analysis to find lemma and root matches.
Linguistic search requires morphology data and a word map to function. It can be disabled by setting options.lemma = false and options.root = false.
For each query token, the engine:
  1. Looks up the token in the word map to find its canonical lemma and root
  2. Searches morphology data for verses containing matching lemmas or roots
  3. Applies AND logic across tokens (all tokens must match)
This layer enables:
  • Finding different forms of the same word (inflections, conjugations)
  • Matching words with the same linguistic root
  • More comprehensive search results beyond exact text matches

3. Fuzzy search layer

The third layer uses Fuse.js as a fallback for tokens that don’t match exactly or linguistically.
Fuzzy search can be disabled entirely by setting options.fuzzy = false in your search options.
Fuzzy search configuration:
  • threshold: 0.5 (maximum allowed distance for a match)
  • distance: 100 (how far to search for patterns)
  • ignoreLocation: true (match anywhere in the text)
  • minMatchCharLength: 3 (minimum characters required)
  • Searches both: standard and uthmani text fields
Adaptive threshold:
If high-quality fuzzy matches exist (score ≤ 0.25), the cutoff is tightened to 0.35 to filter out weaker matches.

Combined search flow

The main search() function orchestrates all three layers:
Process:
  1. Execute simple search and linguistic search in parallel
  2. Merge results and deduplicate by verse ID (gid)
  3. Compute scores for all matched verses
  4. Sort by score (highest first)
  5. Apply pagination
  6. Return results with metadata (counts, pagination info)
Deduplication ensures each verse appears only once in results, even if it matches through multiple layers.

Why this architecture?

This multi-layered approach provides: ✓ Precision: Exact matches score highest
✓ Recall: Linguistic matching finds related forms
✓ Flexibility: Fuzzy search catches typos and variants
✓ Relevance: Scoring prioritizes better matches
✓ Performance: Each layer can be enabled/disabled based on needs
For most use cases, enable all layers with { lemma: true, root: true, fuzzy: true } (fuzzy is enabled by default).