Elasticsearch client for Kotlin: complete guide
Elasticsearch is a powerful distributed search engine based on Lucene. To work with it from Kotlin applications, the official Elasticsearch Java Client is used, which is fully compatible with Kotlin due to its proximity to the JVM. In this article, we will cover how to configure the client, perform basic operations (indexing, search, deletion), and use advanced features such as aggregations and filtering.
Connection and setup
First, add the dependency in build.gradle.kts (or build.gradle):
// build.gradle.ktsdependencies { implementation("co.elastic.clients:elasticsearch-java:8.15.0") implementation("com.fasterxml.jackson.core:jackson-databind:2.17.0") implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.17.0")}Then create the client:
import co.elastic.clients.elasticsearch.ElasticsearchClientimport co.elastic.clients.json.jackson.JacksonJsonpMapperimport co.elastic.clients.transport.rest_client.RestClientTransportimport org.apache.http.HttpHostimport org.elasticsearch.client.RestClient
fun createClient(): ElasticsearchClient { val restClient = RestClient.builder( HttpHost("localhost", 9200, "http") ).build()
val transport = RestClientTransport(restClient, JacksonJsonpMapper()) return ElasticsearchClient(transport)}
val client = createClient()Basic operations
Indexing a document
Create a data class to represent the data:
data class Product( val id: String, val name: String, val price: Double, val category: String)Indexing is done as follows:
suspend fun indexProduct(product: Product) { client.index { i -> i.index("products") .id(product.id) .document(product) }}
// Example callval product = Product("1", "Laptop", 999.99, "Electronics")runBlocking { indexProduct(product) }Search by fields
suspend fun searchByName(name: String): List<Product> { val response = client.search<Product>({ s -> s.index("products") .query { q -> q.match { m -> m.field("name") .query(name) } } }, Product::class.java)
return response.hits().hits().map { it.source()!! }}Deleting a document
suspend fun deleteProduct(id: String) { client.delete { d -> d.index("products") .id(id) }}Filtering and aggregations
Elasticsearch supports complex queries. For example, searching for products in a price range with aggregation by category:
suspend fun searchWithAggregation(minPrice: Double, maxPrice: Double) { val response = client.search<Product>({ s -> s.index("products") .query { q -> q.range { r -> r.field("price") .gte(minPrice.toString()) .lte(maxPrice.toString()) } } .aggregations("by_category") { a -> a.terms { t -> t.field("category") } } }, Product::class.java)
// Get aggregation results val categories = response.aggregations() ?.get("by_category") ?.sterms() ?.buckets() ?.map { "${it.key()}: ${it.docCount()}" } ?: emptyList()
println("Categories: $categories")}Batch processing (Bulk API)
For mass indexing, use bulk