Indexing the Works of Shakespeare in Elasticsearch - Part 1, Infrastructure as Code
Full source code available here.
- Part 1 - Infrastructure as Code
- Part 2 - Bulk Indexing
- Part 3 - Sending the Lines to Kinesis
- Part 4 - Searching via Web API in .Net 5
WARNING - be careful when using this, Kinesis costs money and is not on the AWS free tier. As I write this post, a couple of Elasticsearch instance types are included with the free tier, but you can only have one instance running at a time. I made a mistake and spun up two Elasticsearch instances for a few days and ran up a small bill. I got in touch with AWS support, explained what I was doing, and they refunded me, very helpful and understanding.
This is part one of a four-parter where I’m going to show how to index the complete works of Shakespeare in Elasticsearch. This first part will set up the infrastructure on AWS. The second will go through the lambda that bulk loads data into Elasticsearch. The third will show how to, in Node.js, create the index on the Elasticsearch domain, read the works of Shakespeare from CSV and send to Kinesis, and the fourth will put a .NET 5 Web Api in front of the Elasticsearch cluster.
A few weeks ago I wrote a post describing how to get Elasticsearch up and running on AWS using Pulumi. It was a simple approach with the expectation that the user would send documents directly to Elasticsearch for indexing. This is fine if all you are doing are some experiments, but if you are loading a lot of data and especially if you are sending the data in one document at a time you can easily overwhelm a small Elasticsearch instance and get socket timeouts or run simply run out of sockets.
One way to reduce the likelihood of this occurring is to make bulk requests to index documents in Elasticsearch - instead of sending one document per request, send 100 or 1,000.
Another approach is to use AWS Kinesis in combination with bulk indexing.
Kinesis is a reliable service that you can send thousands (or millions) of individual documents to, these documents are picked up in batches by a lambda that in turn sends them in bulk to Elasticsearch.
If for some reason the lambda fails to process the documents, Kinesis will deliver them to the lambda again to retry indexing.
What Infrastructure is Needed
Quite a lot is needed to get this up and running.
On the IaC side -
- An AWS Role
An AWS policy attachment
A Kinesis stream
An Elasticsearch instance
An AWS Lambda
The code the Lambda will execute
A mapping between the Kinesis stream and the Lambda
Outside of IaC, the following is needed and will be shown in upcoming posts -
- An Elasticsearch mapping document
A tool to send data to Kinesis for indexing
I also want to limit access to Elasticsearch service to my IP address, this is easy to figure out with a call to an API like
The lambda needs a zip file with all my Node.js code. Normally this would be of your CI/CD pipeline, but I want to do this all in one so it’s included here. BEWARE, I was not able to create a valid zip for the AWS lambda with
ZipFile.CreateFromDirectory, instead, I used
By default, Pulumi suffixes the names of your resources with a random string, I don’t like this so I explicitly set names on everything. There is a little method at the top of the class to help with adding a prefix to resource names like “test-01-”, or whatever you want.
The IaC code starts with a query to a third-party API to get the IP address my computer is using, there doesn’t seem to be an easy way to avoid using a call
.Result on the
I then zip up the Lambda source, this is not what you would normally do when deploying a serious application but it’s useful for this demo. As mentioned above I’m using
Ionic.Zip because I could not get the zip file created by
IP address figured out, zip file in place, now I can start building the infrastructure.
Here it all is - this creates the role, policy attachment, Kinesis Stream, Elasticsearch domain, Lambda, Kinesis mapping to Lambda, and output the URL of the Elasticsearch domain.
Finally, I want to print out the URL of the Elasticsearch domain.
That’s it, now all that is left is to deploy and wait…quite…a…while…for Elasticsearch to startup, sometimes as much as 20 minutes.
To deploy run -
And now you wait.
Part two coming soon.
Full source code available here.
- Indexing the Works of Shakespeare in Elasticsearch – Part 3, Sending the Lines to Kinesis
- Indexing the Works of Shakespeare in Elasticsearch - Part 2, Bulk Indexing
- C# and AWS Lambdas, Part 5 – Updating the Zip in S3 and Updating the Running Lambda, with Pulumi IaC
- C# and AWS Lambdas, Part 4 – Storing the Zip in S3, Setup with Pulumi IaC
- C# and AWS Lambdas, Part 3 – Pulumi IaC for Web API and an API Gateway