Elasticsearch in Vapor: Getting Started

In this tutorial, you’ll set up a Vapor server to interact with an Elasticsearch server running locally with Docker to store and retrieve recipe documents. By Christian Weinberger.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 4 of 4 of this article. Click here to view the first page.

Testing Search

Build and run. Before testing search, run this command in Terminal to add another recipe:

curl -X "POST" "http://localhost:8080/api/recipes" \
     -H 'Content-Type: application/json; charset=utf-8' \
     -d $'{
  "name": "Banana Pie",
  "ingredients": [
    "Banana",
    "Sugar",
    "Milk",
    "Vanilla",
    "Egg yolks",
    "Baked pastry shell"
  ],
  "description": "If you like bananas, this is for you",
  "instructions": "Mix all the ingredients. Enjoy!"
}'

Your Vapor server returns your new recipe, along with its Elasticsearch id:

{"ingredients":["Banana","Sugar","Milk","Vanilla","Egg yolks","Baked pastry shell"],"id":"3ZQafnEBLVx2dJNClFTE","name":"Banana Pie","description":"If you like bananas, this is for you","instructions":"Mix all the ingredients. Enjoy!"}

Now that you have two recipes in your database, run this command to test if a partial search results in a tasty apple cake:

curl "http://localhost:8080/api/recipes/search?term=app"

Here’s what this search finds:

[{"ingredients":["Apple","Cake"],"id":"3JT0fXEBLVx2dJNCr1QE","name":"Apple Cake","description":"As easy as apple pie.","instructions":"Mix apple with cake."}]

Great, it found your apple cake! But there’s a reason why you added a banana pie recipe.

Run this command to search for pies:

curl "http://localhost:8080/api/recipes/search?term=pie"

The search returns both recipes:

[{"ingredients":["Apple","Cake"],"id":"3JT0fXEBLVx2dJNCr1QE","name":"Apple Cake","description":"As easy as apple pie.","instructions":"Mix apple with cake."},
{"ingredients":["Banana","Sugar","Milk","Vanilla","Egg yolks","Baked pastry shell"],"id":"3ZQafnEBLVx2dJNClFTE","name":"Banana Pie","description":"If you like bananas, this is for you","instructions":"Mix all the ingredients. Enjoy!"}]

As you can see, it returns two results: the apple cake in the first position and the banana pie in the second. This happens because both recipes contain the term pie in their data. It’s in the apple cake’s description and in the banana pie’s name and description.

As you see, it’s a good idea to prioritize hits in the name and ingredients fields over matching terms in the description field.

Adding Weighted Search

To make results in name and ingredients more relevant, your next step is to add the boost operator, ^, to your searchTerm.

In RecipeFinderController.swift, replace let searchTerm = "(name:*\(term)* OR description:*\(term)* OR ingredients:*\(term)*)" in searchHandler(_:) with the following:

let searchTerm = "(name:*\(term)*^5 OR description:*\(term)* OR ingredients:*\(term)*^2)"

This boosts any matches in name by five and in ingredients by two.

Now build and run again, then retry the search for pie:

curl "http://localhost:8080/api/recipes/search?term=pie"

This time, the results put the banana pie recipe first, because the search term in the name banana pie weighs more than the search term in the description, “As easy as apple pie“.

[{"ingredients":["Banana","Sugar","Milk","Vanilla","Egg yolks","Baked pastry shell"],"id":"3ZQafnEBLVx2dJNClFTE","name":"Banana Pie","description":"If you like bananas, this is for you","instructions":"Mix all the ingredients. Enjoy!"},
{"ingredients":["Apple","Cake"],"id":"3JT0fXEBLVx2dJNCr1QE","name":"Apple Cake","description":"As easy as apple pie.","instructions":"Mix apple with cake."}]

Nice work — you did it! But before you go off to enjoy some delicious recipes, take a moment to clean up.

Cleaning Up

Stop your Xcode project to stop the Vapor server.

To stop the Elasticsearch container and remove it from your system, run these commands in Terminal:

docker stop elasticsearch
docker rm $(docker ps -a -q -f status=exited)

You named the container when you started it, which makes it easier to stop it — you don’t have to search for its ID. The second command finds all exited container processes and removes them.

To remove the Elasticsearch image, first find its IMAGE ID:

docker images

Your output will look similar to this:

docker.elastic.co/elasticsearch/elasticsearch   7.6.2   f29a1ee41030  ...

Then use its IMAGE ID to remove it. Be sure to replace the IMAGE ID with your own:

docker rmi f29a1ee41030

Congratulations! You’ve learned how to set up a search with Elasicsearch in Vapor and how to clean it up when you’re done.

Where to Go From Here?

You can download the completed Recipe Finder Web API project using the Download Materials button at the top or bottom of this page.

In the completed project, you’ll find some implementations that this tutorial doesn’t cover. Instructions are in the project’s README.md file:

  • DeleteIndexCommand: Useful to delete your index.
  • ImportRecipesCommand: An example of how to import data into Elasticsearch via a command. If you deal with a lot of data in production, you should have a look at the Elasticsearch Bulk API instead.

Learn more about Elasticsearch by reviewing its comprehensive documentation at Elasticsearch Reference.

I hope you enjoyed this tutorial. If you have any questions or feedback, please join the forum discussion below.