Skip to Content
Course content

207: Elasticsearch Integration with Ruby

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Imagine you're running a massive physical archive of historical newspapers. If I ask you, "Find me the specific article from July 12th, 1924, about the local bake sale," you can go straight to the shelf, find the date, and pull the page. That's how a traditional relational database works—it's great at finding specific records via a known key or a strict relationship.

But what if I ask, "Find me every article from the last fifty years that mentions 'steam-powered carriages' or 'horseless wagons' in a way that sounds optimistic"? Now you're in trouble. You'd have to read every single page of every single newspaper in the building. You'd be there for years. To solve this, you'd create a giant index at the back of the room: a list of every unique word ever printed, and next to each word, a list of every page where it appears. Instead of reading the newspapers, you check the index first, get the page numbers, and jump straight to the content.

That index is exactly what Elasticsearch is. In Ruby, we aren't replacing our database; we're adding this "index" on top of it to handle the heavy lifting of full-text search.

Connecting Ruby to the Engine

First, you'll need the elasticsearch gem. I usually recommend keeping your Elasticsearch client in a singleton or a dedicated configuration class so you aren't spinning up new connections every time a user hits the search bar.

require 'elasticsearch'

# In a real app, this URL would come from an environment variable
client = Elasticsearch::Client.new(url: 'http://localhost:9200', log: true)

The log: true part is a lifesaver when you're starting out. It lets you see the actual JSON being sent to the server in your terminal. If your search isn't returning what you expect, the JSON is where the truth lives.

Feeding the Index

Let's say we're building a product catalog for a high-end electronics store. We have a Product model in our database, but we want to index it in Elasticsearch so users can search for things like "noise cancelling headphones" without us having to write a dozen complex SQL LIKE queries.

Indexing is the process of taking your Ruby object and pushing it into the Elasticsearch "index" (which is conceptually like a table in SQL).

product_data = {
  name: "Sony WH-1000XM5",
  description: "Industry leading noise canceling overhead headphones with crystal clear sound.",
  category: "Audio",
  price: 399.99
}

# We 'index' the document into a specific index called 'products'
# The 'id' should match your database ID for easy synchronization later
client.index(index: 'products', id: 1, body: product_data)

I've seen a lot of developers make the mistake of indexing everything. Don't do that. Only index the fields you actually intend to search or filter by. If you have a created_at timestamp that no one will ever search for, leave it out. It keeps the index lean and the searches fast.

Finding the Needle in the Haystack

This is where the magic happens. Instead of looking for an exact match, we use a match query. Elasticsearch doesn't just look for the exact string; it analyzes the text, handles stemming (treating "running" and "run" as the same root), and ranks results by relevance.

search_query = "noise cancelling"

response = client.search(index: 'products', body: {
  query: {
    match: {
      description: search_query
    }
  }
})

# Elasticsearch returns a deep hash. We want the 'hits'
results = response['hits']['hits']

results.each do |hit|
  puts "Found: #{hit['_source']['name']} (Score: #{hit['_score']})"
end

Notice that _score value? That's the "secret sauce." Elasticsearch calculates how well the document matches the query. If a product mentions "noise cancelling" five times, it'll likely rank higher than one that mentions it once. You get a sophisticated search experience with about ten lines of Ruby code.




📋 Practical Task

Build a Gourmet Recipe Keyword Search

Your task is to implement a basic search integration for a recipe application. You are provided with a local Elasticsearch instance running on port 9200.

Requirements:

  • Initialize an Elasticsearch::Client.
  • Create an index named recipes.
  • Index three distinct recipe documents. Each document must have a title, ingredients (as a string), and difficulty (e.g., "Easy", "Medium", "Hard").
  • Write a search method that takes a keyword (like "chocolate" or "spicy") and returns only the title of the recipes that match.
  • Test your implementation by searching for a word that appears in the ingredients of one recipe but not the title, verifying that Elasticsearch still finds it.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.