Elasticsearch клиент для Swift (iOS/macOS): интеграция и примеры

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Elasticsearch клиент для Swift (iOS/macOS)

Elasticsearch — это мощная распределённая поисковая система, построенная на основе Apache Lucene. Для разработчиков под iOS и macOS доступен официальный клиент elasticsearch-swift, который предоставляет удобный интерфейс для работы с Elasticsearch из приложений на Swift. Библиотека полностью поддерживает REST API Elasticsearch, включая индексацию, поиск, агрегации и управление кластером.

Установка и настройка

Клиент распространяется через Swift Package Manager (SPM). Для добавления в проект:

// В Package.swift
dependencies: [
    .package(url: "https://github.com/elastic/elasticsearch-swift.git", from: "8.10.0")
]

Или через Xcode: File → Add Packages → введите URL репозитория. После установки импортируйте библиотеку:

import Elasticsearch

Основные возможности

  • Индексация документов — добавление, обновление и удаление записей в индексах.
  • Поиск — полнотекстовый, по полям, с фильтрами и сортировкой.
  • Агрегации — статистические вычисления, группировки, гистограммы.
  • Управление кластером — создание/удаление индексов, настройка шардов и реплик.
  • Поддержка async/await — асинхронные запросы с использованием современной модели Swift Concurrency.

Пример использования: подключение и индексация

Создадим клиент и проиндексируем несколько документов:

import Elasticsearch

let client = ElasticsearchClient(
    host: "https://your-cluster-url:9200",
    apiKey: "your-api-key"
)

struct Book: Codable {
    let id: String
    let title: String
    let author: String
    let year: Int
}

let books = [
    Book(id: "1", title: "Swift Programming", author: "John Doe", year: 2023),
    Book(id: "2", title: "iOS Development", author: "Jane Smith", year: 2024)
]

for book in books {
    let response = try await client.index(
        index: "books",
        id: book.id,
        body: book
    )
    print("Indexed: \(response.result)")
}

Поиск с использованием Query DSL

Elasticsearch поддерживает мощный язык запросов. Пример полнотекстового поиска:

import Elasticsearch

let query: [String: Any] = [
    "query": [
        "bool": [
            "must": [
                ["match": ["title": "Swift"]]
            ],
            "filter": [
                ["range": ["year": ["gte": 2023]]]
            ]
        ]
    ]
]

let searchResponse = try await client.search(
    index: "books",
    body: query
)

if let hits = searchResponse.hits?.hits {
    for hit in hits {
        if let source = hit.source {
            let book = try JSONDecoder().decode(Book.self, from: source)
            print("Found: \(book.title) by \(book.author)")
        }
    }
}

Агрегации для аналитики

Пример подсчёта количества книг по годам:

let aggregationQuery: [String: Any] = [
    "size": 0,
    "aggs": [
        "by_year": [
            "terms": ["field": "year", "size": 10]
        ]
    ]
]

let aggResponse = try await client.search(
    index: "books",
    body: aggregationQuery
)

if let buckets = aggResponse.aggregations?["by_year"] as? [String: Any],
   let bucketList = buckets["buckets"] as? [[String: Any]] {
    for bucket in bucketList {
        let year = bucket["key"] as? Int ?? 0
        let count = bucket["doc_count"] as? Int ?? 0
        print("\(year): \(count) books")
    }
}

Управление индексами

Создание и удаление индекса с настройками:

let settings: [String: Any] = [
    "settings": [
        "number_of_shards": 2,
        "number_of_replicas": 1
    ],
    "mappings": [
        "properties": [
            "title": ["type": "text"],
            "author": ["type": "keyword"],
            "year": ["type": "integer"]
        ]
    ]
]

// Создание индекса
let createResponse = try await client.indices.create(
    index: "books",
    body: settings
)
print("Index created: \(createResponse.acknowledged)")

// Удаление индекса
let deleteResponse = try await client.indices.delete(index: "books")
print("Index deleted: \(deleteResponse.acknowledged)")

Обработка ошибок

Клиент генерирует исключения при сетевых проблемах или ошибках Elasticsearch. Рекомендуется оборачивать вызовы в do-catch:

do {
    let response = try await client.search(index: "books", body: query)
    // обработка результата
} catch let error as ElasticsearchError {
    print("                    

Рекомендаций