elasticlunr.js

repository·master·Indexed 24 days ago

https://github.com/weixsong/elasticlunr.js

A lightweight full-text search engine for JavaScript optimized for browser-side and offline search. It provides a flexible alternative to Lunr.js with features including query-time boosting, smaller index sizes, and a scoring mechanism similar to Elasticsearch/Lucene. It supports simple string searches, field-specific searches, and a complex Query DSL with BoolQuery, MatchQuery, TermsQuery, and NotQuery.

Tokens
3.7K
Snippets
8
Records
22
Agent score
83%

What's inside elasticlunr.js

  1. Key features of Elasticlunr.js

    master

    Elasticlunr.js is a lightweight alternative to Lunr.js designed for browser and offline search. Key advantages include:

    • Query-Time Boosting: Adjust field weights during the search process rather than at index time.
    • Improved Performance: Faster computation by removing the need to compute document and query vectors (unlike Lunr.js).
    • Smaller Index Size: Does not store a TokenCorpus, resulting in index files approximately half the size of Lunr.js. Users can further reduce size by disabling original document storage.
    • Advanced Scoring: Uses a scoring mechanism similar to Elasticsearch/Lucene, combining Boolean, TF/IDF, and Vector Space models for reliable ranking.
    • Field Search: Granular control over which fields are indexed and searched.
  2. Install and use elasticlunr in Node.js

    master

    Install the package via npm:

    npm install elasticlunr

    Then require it in your project:

    var elasticlunr = require('elasticlunr');
    
    var index = elasticlunr(function () {
        this.addField('title');
        this.addField('body');
    });
    
    index.addDoc({
        "id": 1,
        "title": "Oracle released its latest database",
        "body": "..."
    });
    
    const results = index.search("Oracle");
    var elasticlunr = require('elasticlunr');
    
    var index = elasticlunr(function () {
        this.addField('title')
        this.addField('body')
    });
    
    var doc1 = {
        "id": 1,
        "title": "Oracle released its latest database Oracle 12g",
        "body": "Yestaday Oracle has released its new database Oracle 12g, this would make more money for this company and lead to a nice profit report of annual year."
    }
    
    index.addDoc(doc1);
    index.search("Oracle database profit");
  3. Save and load an index

    master

    To avoid rebuilding the index every time, you can build it once, serialize it to JSON, and load it later.

    Saving an index

    Use JSON.stringify(index) to serialize the index. This invokes the elasticlunr.Index.prototype.toJSON method internally.

    Loading an index

    Use elasticlunr.Index.load(jsonObject) to restore a previously saved index.

    // Saving (Node.js example)
    fs.writeFile('./index.json', JSON.stringify(idx), function (err) {
      if (err) throw err;
      console.log('done');
    });
    
    // Loading
    var indexDump = JSON.parse(fileContent);
    var index = elasticlunr.Index.load(indexDump);
    // Saving
    fs.writeFile('./example/example_index.json', JSON.stringify(idx), function (err) {
      if (err) throw err;
      console.log('done');
    });
    
    // Loading
    var indexDump = JSON.parse(indexDump)
    window.idx = elasticlunr.Index.load(indexDump)
  4. Use non-English languages with lunr-languages

    master

    By default, elasticlunr.js supports English. To support other languages, you must use the lunr-languages package.

    In the Browser

    Include the stemmer support and the specific language script, then use this.use(elasticlunr.lang) during initialization.

    <script src="lunr.stemmer.support.js"></script>
    <script src="lunr.de.js"></script>
    <script>
      var index = elasticlunr(function () {
        this.use(elasticlunr.de);
        this.addField('title');
      });
    </script>

    In Node.js

    Require the support files and pass the elasticlunr instance to them, then use this.use().

    var elasticlunr = require('elasticlunr');
    require('./lunr.stemmer.support.js')(elasticlunr);
    require('./lunr.de.js')(elasticlunr);
    
    var index = elasticlunr(function () {
        this.use(elasticlunr.de);
        this.addField('title');
    });
    // Node.js example for German
    var elasticlunr = require('elasticlunr');
    require('./lunr.stemmer.support.js')(elasticlunr);
    require('./lunr.de.js')(elasticlunr);
    
    var index = elasticlunr(function () {
        this.use(elasticlunr.de);
        this.addField('title')
        this.addField('body')
    });
  5. How the Query DSL works

    master

    Elasticlunr uses a QueryRepository to parse query objects into specific Query class instances.

    When you provide a query object like { match: { field: 'value' } }, the QueryRepository identifies the match key, looks up the corresponding parser, and returns a MatchQuery instance. This allows for a nested, JSON-like syntax to build complex search logic.

    Commonly used query types registered in the repository include:

    • match
    • terms
    • bool
    • not
    • match_all
  6. Add, remove, and update documents

    master

    Once the index is configured, you can manage documents using the following methods:

    • addDoc(doc): Adds a JSON document to the index. Fields not configured in the index setup will not be indexed.
    • removeDoc(doc): Removes a document from the index. This removes each token of that document's fields from the inverted index.
    • updateDoc(doc): Updates an existing document in the index.

    Note: If you used saveDocument(false) during setup, updating and removing documents may be difficult as the original data is not stored.

  7. Perform simple queries with `index.search()`

    master

    To perform a basic search, pass a query string to the search method. The method returns an array of result objects, sorted in descending order by their similarity score. Each object contains:

    • ref: The document reference (e.g., the ID).
    • score: The similarity measurement.
    index.search("Oracle database profit");
  8. Search the index

    master

    Elasticlunr.js provides several ways to perform searches:

    Search for a query string across all indexed fields.

    index.search("query string");

    2. Query-Time Boosting

    Pass a configuration object to assign different weights (boosts) to specific fields for a single query. This allows for flexible ranking without rebuilding the index.

    index.search("query string", {
        fields: {
            title: {boost: 2},
            body: {boost: 1}
        }
    });

    Search for specific terms within specific fields by passing an object.

    index.search({
      title: 'database',
      body:  'profit',
    });

    Search Results

    The search returns an array of objects containing the document reference (ref) and a relevance score:

    [
      {
        "ref": 1,
        "score": 0.5376053707962494
      }
    ]
    // Example of Query-Time Boosting
    index.search("Oracle database profit", {
        fields: {
            title: {boost: 2},
            body: {boost: 1}
        }
    });
  9. Build a search index

    master

    To create a search index, call elasticlunr() and configure the fields you want to index and the reference field. If you do not specify fields, no fields will be searchable. By default, the reference field is 'id'. You can use this.setRef('fieldName') to change this.

    You can also call this.saveDocument(false) during configuration to prevent the index from storing the original JSON documents, which significantly reduces the index size (useful for offline search), but makes updating or deleting documents more difficult.

    var index = elasticlunr(function () {
        this.addField('title');
        this.addField('body');
        this.setRef('id');
        this.saveDocument(false); // Optional: reduces index size
    });
  10. Manage stop words

    master

    Elasticlunr.js includes ~120 default English stop words. You can clear them or add your own.

    • Remove default stop words: Use elasticlunr.clearStopWords().
    • Add customized stop words: Pass an array of strings to elasticlunr.addStopWords(list).
    // Remove defaults
    elasticlunr.clearStopWords();
    
    // Add custom words
    var customized_stop_words = ['an', 'hello', 'xyzabc'];
    elasticlunr.addStopWords(customized_stop_words);
    elasticlunr.clearStopWords();
    
    var customized_stop_words = ['an', 'hello', 'xyzabc'];
    elasticlunr.addStopWords(customized_stop_words);
  11. Configure advanced queries with boosting, boolean logic, and expansion

    master

    You can pass a configuration object to index.search() to fine-tune how queries are executed.

    Query-Time Boosting

    Specify which fields to search and assign a boost weight to them. If configured, the search will only occur in these specified fields.

    Boolean Model

    Set the logic for combining terms using bool. Supported values are "OR" (default) and "AND". You can set this globally or per-field. Field-level settings overwrite global settings.

    Token Expansion

    Set expand: true to increase RECALL. This expands query tokens to match partial words (e.g., searching "micro" might return "microwave"). Expanded results are penalized in the scoring mechanism. This can also be configured at the field level.

    index.search("micro", {
        fields: {
            title: {
                boost: 2,
                bool: "AND",
                expand: false
            },
            body: {
                boost: 1
            }
        },
        bool: "OR",
        expand: true
    });