Lexicor

pub package

Lexicor is a strictly typed, highly optimized, offline interface for the Open English WordNet.

Powered by an embedded SQLite database โ€” no external APIs, no raw text parsing.

โœจ Features

  • ๐Ÿš€ Ultra Fast: Microsecond-level lookups (~20ยตs on disk). WITHOUT ROWID tables, covering indexes, and LRU result caching.
  • ๐Ÿ”’ Strictly Typed: Concept, SpeechPart, RelationType, DomainCategory โ€” no magic strings or integers anywhere.
  • ๐Ÿง  Morphology Aware: Automatic stem resolution. "ran" โ†’ "run", "better" โ†’ "good".
  • ๐Ÿ“– Optional Definitions: Pass withDefinitions: true to get WordNet glosses on every concept โ€” or keep the default lightweight build when you don't need them.
  • ๐Ÿ”— Rich Relations: Semantic (Concept-to-Concept) and Lexical (Word-to-Word) relations, filterable by type in SQL.
  • ๐ŸŒฒ Recursive Traversal: Walk hypernym/hyponym chains to arbitrary depth via a single SQLite recursive CTE.
  • โšก Dual Storage Modes: Disk mode (instant startup) or Memory mode (fastest queries).

๐Ÿ“ฆ Installation

dependencies:
  lexicor: ^0.2.0

๐Ÿš€ Quick Start

import 'package:lexicor/lexicor.dart';

void main() async {
  final lexicor = await Lexicor.init();           // lightweight, no definitions
  // final lexicor = await Lexicor.init(withDefinitions: true); // full mode

  final result = lexicor.lookup('bank');
  print('Found ${result.concepts.length} concepts for "${result.query}"');

  for (final concept in result.concepts) {
    print('[${concept.part.label}] ${concept.category.label}');
    if (concept.definition != null) print('  ${concept.definition}');

    final hypernyms = lexicor.related(concept, type: RelationType.hypernym);
    for (final rel in hypernyms.items) {
      print('  -> is a type of: ${rel.word}');
    }
  }

  lexicor.close();
}

๐Ÿ“– Usage Guide

Initialization

// Light mode โ€” no definitions (~28 MB asset, default)
final lexicor = await Lexicor.init();

// Full mode โ€” definitions + usage examples (~40 MB asset)
final lexicor = await Lexicor.init(withDefinitions: true);

// Memory mode โ€” copy DB into RAM for fastest repeated queries
final lexicor = await Lexicor.init(
  mode: StorageMode.inMemory,
  withDefinitions: true,
);
Flag Asset Concept.definition examples() Best for
withDefinitions: false (default) dictionary.sqlite ~28 MB null [] Mobile, CLI, embedding
withDefinitions: true dictionary_full.sqlite ~40 MB populated sentences Dictionaries, NLP

Definitions

final lexicor = await Lexicor.init(withDefinitions: true);
final result = lexicor.lookup('bank');
for (final concept in result.concepts) {
  print(concept.definition);
  // "a financial institution that accepts deposits..."
  // "a long ridge or pile..."
}

concept.definition is always null in light mode โ€” safe to use without checking the mode:

final def = concept.definition ?? '(no definition)';

Usage Examples

final lexicor = await Lexicor.init(withDefinitions: true);
final concept = lexicor.lookup('run').primary!;

for (final example in lexicor.examples(concept)) {
  print(example); // "she ran to catch the bus"
}

Returns an empty list in light mode.

Synonyms

final concept = lexicor.lookup('car').primary!;
final syns = lexicor.synonyms(concept);
// ['car', 'auto', 'automobile', 'motorcar']

These are strict synonyms โ€” words that share the exact same synset. For broader similarity, use related(concept, type: RelationType.similar).

Recursive Traversal

Walk a relation chain to arbitrary depth in a single DB call:

final dog = lexicor.lookup('dog').primary!;
final chain = lexicor.traverse(dog, RelationType.hypernym, maxDepth: 5);

for (final word in chain) {
  print('${'  ' * word.depth}${word.word}');
}
// canine
//   carnivore
//     placental
//       mammal
//         ...

traverse uses a SQLite recursive CTE โ€” the entire hierarchy walk is done in one round-trip. Only works for relations where RelationType.isRecursive is true (hypernym, hyponym, partMeronym, etc.).

Relationships

final rels = lexicor.related(concept);

// SQL-level type filter โ€” no wasted data transfer
final hypernyms = lexicor.related(concept, type: RelationType.hypernym);

// Or filter the result object
final semantic = rels.semantic;            // Concept-to-Concept links
final lexical  = rels.lexical;             // Word-to-Word links
final antonyms = rels.byType(RelationType.antonym);

Batch Lookup

final results = lexicor.lookupBatch(['run', 'walk', 'swim', 'run']);
// 'run' is only queried once; the second entry is served from cache.
results['run']?.concepts.length;

Morphology

// Automatic during lookup:
lexicor.lookup('running').resolvedForms; // ['running', 'run']

// Direct lemmatization:
lexicor.lemmatize('ran', SpeechPart.verb);        // 'run'
lexicor.lemmatize('better', SpeechPart.adjective); // 'good'

Flutter Integration

import 'package:path_provider/path_provider.dart';
import 'package:flutter/services.dart';
import 'package:lexicor/lexicor.dart';

Future<Lexicor> initLexicor({bool withDefinitions = false}) async {
  final assetName = withDefinitions ? 'dictionary_full.sqlite' : 'dictionary.sqlite';
  final dir  = await getApplicationDocumentsDirectory();
  final file = File('${dir.path}/$assetName');

  if (!file.existsSync()) {
    final data = await rootBundle.load('packages/lexicor/assets/$assetName');
    await file.writeAsBytes(data.buffer.asUint8List());
  }

  return Lexicor.init(customPath: file.path, withDefinitions: withDefinitions);
}

๐Ÿ›  Building the Database

Place your oewn.sqlite (~165 MB source file) at tool/db/oewn.sqlite, then:

# Light build only (~28 MB)
dart run tool/build_database.dart tool/db/oewn.sqlite

# Full build only (~40 MB)
dart run tool/build_database.dart tool/db/oewn.sqlite --full

# Both at once
dart run tool/build_database.dart tool/db/oewn.sqlite --all

# Or via melos
melos run build
melos run build:full
melos run build:all

๐Ÿ“Š Database Stats

Component Light Full Description
Words 3.0 MB 3.0 MB ~150k unique lemmas
Concepts 1.36 MB 1.36 MB ~120k Synsets
Senses 3.4 MB 3.4 MB ~210k Word-Concept pairs
Semantic Relations 3.7 MB 3.7 MB Hypernyms, Holonyms, Entailments
Lexical Relations 4.0 MB 4.0 MB Antonyms, Derivations
Indexes ~11 MB ~11 MB COLLATE NOCASE indexes
Definitions โ€” ~10 MB Synset glosses (~120k rows)
Examples โ€” ~2 MB Usage sentences from samples table
Total ~28 MB ~40 MB

๐Ÿ“‚ License

Commercial use requires attribution to the Open English WordNet project in your app's About / Licenses section.

Libraries

lexicor
Lexicor โ€” WordNet for Dart