Elasticsearch клиент для Kotlin: полное руководство
Elasticsearch — это мощная распределённая поисковая система, основанная на Lucene. Для работы с ней из Kotlin-приложений используется официальный клиент Elasticsearch Java Client, который полностью совместим с Kotlin благодаря его близости к JVM. В этой статье мы разберём, как настроить клиент, выполнять основные операции (индексация, поиск, удаление) и использовать продвинутые возможности, такие как агрегации и фильтрация.
Подключение и настройка
Для начала добавьте зависимость в build.gradle.kts (или build.gradle):
// build.gradle.kts
dependencies {
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")
}
Затем создайте клиент:
import co.elastic.clients.elasticsearch.ElasticsearchClient
import co.elastic.clients.json.jackson.JacksonJsonpMapper
import co.elastic.clients.transport.rest_client.RestClientTransport
import org.apache.http.HttpHost
import 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()
Основные операции
Индексация документа
Создайте data class для представления данных:
data class Product(
val id: String,
val name: String,
val price: Double,
val category: String
)
Индексация выполняется так:
suspend fun indexProduct(product: Product) {
client.index { i ->
i.index("products")
.id(product.id)
.document(product)
}
}
// Пример вызова
val product = Product("1", "Ноутбук", 999.99, "Электроника")
runBlocking { indexProduct(product) }
Поиск по полям
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()!! }
}
Удаление документа
suspend fun deleteProduct(id: String) {
client.delete { d ->
d.index("products")
.id(id)
}
}
Фильтрация и агрегации
Elasticsearch поддерживает сложные запросы. Например, поиск товаров в ценовом диапазоне с агрегацией по категориям:
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)
// Получаем результаты агрегации
val categories = response.aggregations()
?.get("by_category")
?.sterms()
?.buckets()
?.map { "${it.key()}: ${it.docCount()}" }
?: emptyList()
println("Категории: $categories")
}
Пакетная обработка (Bulk API)
Для массовой индексации используйте bulk:
suspend fun bulkIndexProducts(products: List<Product>) {
val bulkRequest = client.bulk { b ->
products.forEach { product ->
b.operations { op ->
op.index { idx ->
idx.index("products")
.id(product.id)
.document(product)
}
}
}
}
if (bulkRequest.errors()) {
println("Ошибки при индексации: ${bulkRequest.items().filter { it.error() != null }}")
} else {
println("Успешно проиндексировано: ${products.size}")
}
}
Работа с индексами
Создание индекса с маппингом:
suspend fun createIndexWithMapping() {
client.indices().create { c ->
c.index("products")
.mappings { m ->
m.properties("name") { p ->
p.text { t -> t.analyzer("standard") }
}
.properties("price") { p ->
p.double { d -> d }
}
.properties("category") { p ->
p.keyword { k -> k Также в библиотеке
tsyringe для TypeScript: полное руководство с примерами
Мониторинг приложений Kotlin: обзор инструментов и библиотек
Тестирование в C# (.NET): полный обзор фреймворков и инструментов
CLI Фреймворк для Rust: полное руководство по разработке утилит
Swagger/OpenAPI генерация для C++: обзор инструментов и библиотек