Getting Started with CBElasticSearch

About Me

  • Michael Born
  • Ortus Solutions
  • Central NY
  • No coronavirus (yet!)

Problem: Search Is Hard

Expectations Are Growing

Users expect search to be:

  • Fast
  • Intelligent
  • Forgiving

Database Search Doesn't Cut It

  • Too slow
  • Does not scale
  • Lacks features
  • Not configurable

CFSearch Doesn't Cut It

  • Limited configuration
  • Does not scale
  • Difficult to update or upgrade
  • Query language is limited

Solution: ElasticSearch

What Is ElasticSearch?

An open-source distributed search server built on Lucene

API-Based

  • Index create/update/delete
  • Document create/update/delete
  • Searching
  • Settings
  • etc.
{
   "properties": {
      "primaryTitle": "The Fellowship Of The Ring",
      "titleType": "movie",
      "runtime_mins": "178",
      "startYear" : "2001",
      "budget" : "93,000,000",
      "box_office_gross": "887,800,000"
   }
}

JSON In

JSON Out

{
    "_index": "flicks",
    "_type": "_doc",
    "_id": "1lH95XABhTaGTn6QUVJH",
    "_version": 1,
    "result": "created",
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 1043003,
    "_primary_term": 3
}

Scales Like the Dickens

ElasticSearch Terms

Index

A collection of documents which are tokenized (indexed) on insert in preparation for search.

Text Analysis (Indexing)

Breaking a text string down into small, self-contained search terms.

Text Analysis (Example)

the quick brown fox jumps over the lazy dog

quick

brown

fox

jumps

over

the

lazy

dog

Mapping

A definition of fields and field types for a specific index.

{
   "primaryTitle"     : "text",
   "titleType"        : "keyword",
   "runtime_mins"     : "integer",
   "startYear"        : "integer",
   "budget"           : "integer",
   "box_office_gross" : "integer"
}

Document

A single record within an index

{
   "primaryTitle": "The Fellowship Of The Ring",
   "titleType": "movie",
   "runtime_mins": "178",
   "startYear" : "2001",
   "budget" : "93,000,000",
   "box_office_gross": "887,800,000"
}

Demo ElasticSearch API

What Is CBElasticSearch?

A CFML wrapper for the ElasticSearch API which provides an easy way to:

  • Connect to ElasticSearch
  • Create and manage Indices
  • Create and manage Documents
  • Search the Index

Installation:
First Steps

Installing ElasticSearch

docker run -d \
    -p 9200:9200 \
    -e "discovery.type=single-node" \
     --name="myApp_ES" \
    elasticsearch:7.5.1

Setup CBElasticSearch

box install cbelasticsearch
// config/Coldbox.cfc

moduleSettings = {
   "cbElasticsearch" : {
       "hosts" : [ {
           "serverProtocol" : "http",
           "serverName"     : "127.0.0.1",
           "serverPort"     : "9200"
       } ],
       "defaultIndex" = "reviews"
   }
}

Indexing Data

Initializing an Index On Application Load

component {

    /**
     * Initialize the ElasticSearch index on app load/reinit
     */
    void function afterConfigurationLoad( event, interceptData ){
        // create index...
    }
}

Creating an Index with IndexBuilder

function buildMyIndex() {
  getInstance( "IndexBuilder@cbElasticsearch" )
      .new(
          "reviews",
         {
            "_doc" = {
                "_all" = { "enabled" = false },
                "properties" = {
                    "title" = { "type" = "text" },
                    "authorName" = { "type" = "integer" },
                    "publishedDate" = { "type" = "text" },
                    "stars" = { "type" = "keyword" },
                    "content" = { "type" = "text" }
                }
            }
        }
  ).save();
}

Create an Index with MappingBuilder

function createBookIndex() {

    getInstance( "IndexBuilder" )
        .new( "books", getInstance( "MappingBuilder@cbElasticSearch" )
            .create( function( mapping ) {
                mapping.text( "title" );
                mapping.object( "author", function( mapping ) {
                    mapping.text( "firstname" );
                    mapping.text( "lastname" );
                } );
            } );
        } );

}

Creating A Document

function insertReview() {
  
  var bookReview = {
     "title" : "'Phantom': Lost in Hyperspace",
     "authorName" : "Rita Kempley",
     "publishedDate" : DateFormat( "1999-05-19" ),
     "stars" : "1",
     "content" : "The Empire strikes out..."
  };
  
  var document = getInstance( "Document@cbElasticsearch" )
     .new(
         index = "reviews",
         type = "_doc",
         properties = bookReview
     );
  document.save();
  
}

Searching with CBElasticSearch

SearchBuilder

function searchByTitle( required string title ) {

    var startDate = createDate( "2018", "12", "31" );
    var endDate = createDate( "2020", "04", "08" );

    var search = getInstance( "SearchBuilder@cbElasticSearch" )
            .new(
                index = "news",
                type = "_doc"
            )
            .match( "title", arguments.title )
            .dateMatch( "publishedDate", startDate, endDate )
            .sort( "publishedDate", "desc" );

    return search.execute();

}

Fuzzy Search

var result = getInstance( "SearchBuilder@cbElasticSearch" )
   .new(
      index = "reviews",
      type = "_doc"
   )
   .match( "content", "star wars" )
   .execute();

Term Query

var result = getInstance( "SearchBuilder@cbElasticSearch" )
   .new(
      index = "reviews",
      type = "_doc"
   )
   .term( "stars", 5 )
   .execute();

Must Match: AND Clause

var result = getInstance( "SearchBuilder@cbElasticSearch" )
   .new(
      index = "reviews",
      type = "_doc"
   )
   .mustMatch( "author", "Luis Majano" )
   .mustMatch( "content", "star wars" )
   .execute();

Should Match: OR Clause

var result = getInstance( "SearchBuilder@cbElasticSearch" )
   .new(
      index = "reviews",
      type = "_doc"
   )
   .shouldMatch( "author", "Luis Majano" )
   .shouldMatch( "author", "Jon Clausen" )
   .execute();

Demo CFSnippets Search

When To Use ElasticSearch

  1. Full-text search
  2. Structured data
  3. Future scaling
  4. Any complex search needs

When NOT to use ElasticSearch

  1. If you don't need full-text search
  2. If you don't have many records
  3. No scalability needs

If You Don't Need It - Don't Use It!

Questions?

Thanks for watching!

Getting Started with CBElasticSearch

By Michael Born

Getting Started with CBElasticSearch

  • 645