I recently built a search form, pulling data from an Elasticsearch index to display search results. I wanted to explain the concept, my goals, and the outcome. This is a basic example of using Elastic for searching, and through this exercise I feel more comfortable tackling more complex use cases in the future.
Below is an example index seen in ElasticVue chrome extension (https://elasticvue.com/). ID's and other data points are blocked to protect the data, but the general structure of the index is still visible. In this example, we can see there is a list of contracts that each have an ID, a CreatedByContactID, a BillingContact, and a BillingContactID.
Let's say this search allows us to input a contact ID, and we want to see the contracts that have a CreatedByContactID or BillingContactID with this value, and we also want to filter any results based on other input criteria, such as a billing contact name and a contract ID (the _id field).
To do this filtering and data extraction from the index, we'll construct a boolean query (https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html), which will allow specifying many different types of fields that we want to search on.
The scoring assigned for this query (aka the calculated relevance of the result) favors matches within the must clause. I can also add filters to this boolean query, although these will not affect the score of the documents returned.
I built a sample form in React as a UI for the searching. Suppose this is my form, and my React application takes in values for each of the fields specified. Within my app, I can take these values and build a query to search the records in my index.
Without going to deep into the infrastructure, I can construct my query in Typescript using an Elasticsearch client (https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/index.html) to make search calls to the existing Elasticsearch index I connect to.
Simply put, this client provides a ".search()" method I will be calling with the constructed query to bring data back to my UI.
Because my query will check on two fields for the same value, I plan to add a multi-match query that checks two fields on the index for the same value. For this particular multi_match, I specified a cross_fields type because I want the input contact ID to check either of the contact fields for that ID. Because I place this multi_match within a 'must' query, these fields must match the id specified and will contribute to the score of the documents returned.
The extra filters will be added to my elastic query simply as filters to search on. These filters must appear in the documents to be returned, and as mentioned earlier, these filters will not contribute to the calculated score of the results.
First, I can build an array of search filters that will be passed back to the query that we will pass into the Elastic client. Each filter has a term and a value to search on.
To add the filters (the ID and Billing Contact), I can push elements to the array.
I can construct the multi-match 'must' fields array similarly.
Assuming we have an existing elasticSearchClient built (please see Elasticsearch documentation to learn how to construct a client for searching), we can pass all of our specifications in and hopefully get back some data from the index.
The output of this code should match the query I outlined at the top of this article. I can use the results in my application and present them back to the user, who will hopefully be seeing the contracts they expected :)
Overall, I learned a lot about constructing queries based on an Elastic index and how to pull out the data I need. I hope this was informative and painted a clearer picture of the concept of constructing boolean queries with bool, must, filter and multi_match queries, especially for those newer to Elasticsearch. I can see how this would be beneficial for quick access to large sets of data and I'm excited to play around more with Elasticsearch.
Thanks for reading and as always feel free to share any thoughts!