Elastic Builder in Node.js: Simplifying Elasticsearch Query Creation
This article will help us understand how we can use elastic-builder tool to simplify the search query syntax for Elasticsearch.
Elasticsearch
Elasticsearch is a distributed search and analytics engine built on Apache Lucene and is majorly known for its fast text searches and real-time indexing and search operations.
What is Elastic Builder?
elastic-builder is a query builder library used to create search query body for Elasticsearch, eliminating the need for complicated raw queries and making the query syntax more readable.
Prerequisite
If you are looking to create simplified Elasticsearch queries, I can
assume that you have:
- basic knowledge of Elasticsearch and query tool
- setup Elasticsearch client
- indexed your desired dataset in Elasticsearch domain on which you can perform search queries
Understanding Elastic Builder through Examples
To understand it better, let’s go over a couple of examples. We’ll start off with a basic example and then, gradually, we will refine our query more in order to get accurate results.
Basic Search Example
Let’s consider a movie dataset and begin with a basic search query example:
{
"query": {
"match": {
"titles": "avenger"
}
}
}
In the above example, we are running a query to find all the movies that have the word ‘avenger’ in their title. We can see that even for a simple match query, the structure for Elasticsearch queries are rather lengthy. Now, we write the same query with the elastic-builder syntax:
esb.requestBodySearch()
.query(esb.matchQuery('titles', 'avenger'));
Note that the above query performs the same function as a raw query and returns identical search results, yet it is more readable and intuitive.
Elasticsearch allows its users to perform more complex searches including those with nested data. As a result, raw queries can become verbose and more susceptible to errors.
Enhancing the Query for Refined Results
Now, you might think that the above structure is not that bad, but what if we modify the above query to make our search results more accurate?
Let’s refine the above query a bit more. We are now searching for movies in which the title includes the word ‘avenger.’ We further refine our results to only include movies released between the years 2011 and 2015 using the range query.
{
"query": {
"bool": {
"must": {
"match": {
"title": "avenger"
}
},
"filter": {
"range": {
"year": {
"gte": "2011",
"lte": "2015",
"format": "yyyy"
}
}
}
}
}
}
You can see that the more we refine our queries for more accurate results, their structure becomes more elaborated. This increasing complexity can make the query less readable and it can cause problems in case of modification.
Writing the same search query with elastic-builder syntax will look like this:
esb.requestBodySearch()
.query(
esb.boolQuery()
.must(esb.matchQuery('title', 'avenger'))
.filter(esb.rangeQuery('year').gte('2011').lte('2015').format('yyyy'))
);
You can see how the structure becomes more concise and readable, making it easier to spot any mistakes made during the writing process.
Moving to a More Complex Search Query
Let’s add more complexity. We want our movie search to also filter movies by genre. To achieve this, we’ve updated the earlier query by incorporating a term query. This will identify all movies in the ‘Adventure’ genre. Additionally, the title should have the word ‘avenger’, and the movie should have been released between the years 2011 and 2015.
{
"query": {
"bool": {
"must": [
{
"term": {
"genres": "Adventure"
}
},
{
"match": {
"title": "avenger"
}
},
{
"range": {
"year": {
"gte": "2011",
"lte": "2015",
"format": "yyyy"
}
}
}
]
}
}
}
Highlighting Issues with Writing Raw Queries
Here are several potential issues that may arise as the complexity of raw query increases:
- Such queries are extensive and can cost code readability.
- There is a higher chance of encountering syntax errors, especially when you are dealing with nested fields.
- Making small modifications can become challenging. Even adding a small filter or query field can become difficult.
- For a new team member in a project, it can be troublesome to understand such a complex structure.
Possible Solution
Using a query builder syntax to craft the same query can address these issues.
esb.requestBodySearch()
.query(
esb.boolQuery().must([
esb.termQuery('genres', 'Adventure'),
esb.matchQuery('title', 'avenger'),
esb.rangeQuery('year')
.gte('2011')
.lte('2015')
.format('yyyy')
]))
Conclusion
In conclusion, elastic-builder simplifies creating Elasticsearch queries. With its clear functions, it reduces the likelihood of making mistakes and is easier to read than JSON structures, making search in Elasticsearch more efficient and user-friendly.
Side Note
elastic-builder, to some extent is compatible with OpenSearch, that’s because Opensearch is a fork of Elasticsearch version 7.10. 2. so if you follow the same query syntax as Elasticsearch it will work.
About Humda Zainab
- LinkedIn Profile — https://www.linkedin.com/in/humda-zainab-764963209/
About Red Buffer
- Website — https://redbuffer.ai/
- Linkedin Page — linkedin.com/company/red-buffer
References for learning
- https://www.elastic.co/guide/en/elasticsearch/reference/7.17/getting-started.html — Quick start with Elasticsearch
- https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html — Official documentation on Elasticsearch with Query DSL
- https://elastic-builder.js.org/docs/ — Official documentation on elastic-builder