ducene

An instant search library for Dart.

Pub Build Status License

Demo

Pub Search

Usage

A simple usage example:

  import 'dart:async';
  import 'package:ducene/analysis.dart';
  import 'package:ducene/document.dart';
  import 'package:ducene/index.dart';
  import 'package:ducene/search.dart';
  import 'package:ducene/store.dart';

  Analyzer st = new StandardAnalyzer();

  // Store the index in memory:
  IndexDirectory directory = new RAMIndexDirectory();
  // To store an index on disk, use this instead:
  //IndexDirectory directory = new FSIndexDirectory(new Directory("testindex"));
  IndexWriter writer = new IndexWriter(directory);
  String text = 'This is the text of #1.';
  Document doc1 = new Document()
    .append('id', '1')
    .append('text', text, analyzer: st)
    .append('filter', 'x')
    .append('cat', 'CAT-A')
    .append('subcat', 'CAT-A-1')
    .append('price', '80');
  text = 'This is the text of #2.';
  Document doc2 = new Document()
    .append('id', '2')
    .append('text', text, analyzer: st)
    .append('filter', 'x')
    .append('cat', ['CAT-B', 'CAT-A'])
    .append('subcat', 'CAT-A-2')
    .append('price', '70');
  text = "the text which 'or' matched";
  Document doc3 = new Document()
    .append('id', '3')
    .append('text', text, analyzer: st)
    .append('filter', 'x')
    .append('cat', 'CAT-C')
    .append('subcat', 'CAT-C-1')
    .append('price', '100');
  await writer.write([doc1, doc2, doc3]);

  // Now search the index:
  IndexReader reader = await DirectoryReader.open(directory);
  IndexSearcher searcher = new IndexSearcher(reader);
  BoolQuery query = new BoolQuery()
      .append('text', 'this text', analyzer: st)
      .addFilter(new TermQuery(new Term('filter', 'x')));
  TopDocs hits = await searcher.search(query, 1000);
  assert(3 == await searcher.count(query));
  assert(3 == hits.totalHits);
  // Iterate through the results:
  for (ScoreDoc hit in hits.scoreDocs) {
    Document hitDoc = await searcher.doc(hit.doc);
    assert(hitDoc.get('text').contains('the text'));
    print('${hitDoc.get('id')} : ${hit.score.toString()}');
    // Highlight:
    String snippet
      = FieldHighlight.getSnippet(query, 'text', hitDoc.get('text'));
    assert(snippet.contains('<b>'));
    print(snippet);
  }

  // Facet + Stats:
  Map<String,FacetValue> mainFacet = await FieldFacet.getCount(hits.docSet,'cat',reader);
  FacetValue mainFacetA = mainFacet['CAT-A'];
  assert (mainFacetA.value == 2);
  FacetValue mainFacetB = mainFacet['CAT-B'];
  assert (mainFacetB.value == 1);
  FacetValue mainFacetC = mainFacet['CAT-C'];
  assert (mainFacetC.value == 1);
  var mainStatsA = await FieldStats.getStats(mainFacetA.docSet, 'price', reader);
  assert(mainStatsA.sum == 150 && mainStatsA.mean == 75);
  var mainStatsB = await FieldStats.getStats(mainFacetB.docSet, 'price', reader);
  assert(mainStatsB.count == 1);
  var mainStatsC = await FieldStats.getStats(mainFacetC.docSet, 'price', reader);
  assert(mainStatsC.min == 100 && mainStatsC.max == 100);

  var subFacetA = await FieldFacet.getCount(mainFacetA.docSet, 'subcat', reader);
  FacetValue subFacetA1 = subFacetA['CAT-A-1'];
  assert (subFacetA1.value == 1);
  FacetValue subFacetA2 = subFacetA['CAT-A-2'];
  assert (subFacetA2.value == 1);
  var subStatsA1 = await FieldStats.getStats(subFacetA1.docSet, 'price', reader);
  assert(subStatsA1.sum == 80);
  var subStatsA2 = await FieldStats.getStats(subFacetA2.docSet, 'price', reader);
  assert(subStatsA2.sum == 70);

Features and bugs

Please file feature requests and bugs at the issue tracker.

Libraries

ducene.analysis

Text analysis.

ducene.document

The logical representation of a Document for indexing and searching.

ducene.index

Code to maintain and access an index.

ducene.search

Code to search an index.

ducene.store

i/o API, used for all index data.

ducene.store.firebase

firebase3-dart: https://github.com/Janamou/firebase3-dart

ducene.store.html

ducene.store.sembast

sembast.dart: https://github.com/tekartik/sembast.dart

ducene.util

Some utility classes.