博客 / 詳情

返回

Easysearch Java SDK 2.0.x 使用指南(二)

在 上一篇文章 中,我們介紹了 Easysearch Java SDK 2.0.x 的基本使用和批量操作。本文將深入探討索引管理相關的功能,包括索引的創建、刪除、開關、刷新、滾動等操作,以及新版 SDK 提供的同步和異步兩種調用方式。

SDK 的對象構建有兩種方式

1. 傳統的 Builder 方式

最基礎的方式,像這樣:

CreateIndexResponse createResponse = client.indices().create(
    new CreateIndexRequest.Builder()
        .index("my-index")
        .aliases("foo",
            new Alias.Builder().isWriteIndex(true).build()
        )
        .build()
);

優點簡單直觀,但稍顯笨重。

2. Lambda 表達式方式

這才是推薦的寫法,簡潔優雅:

CreateIndexResponse createResponse = client.indices()
    .create(c -> c
        .index("my-index")
        .aliases("foo", a -> a
            .isWriteIndex(true)
        )
    );

Lambda 方式不僅代碼少,最大的優點是不用記那麼多 Builder 類名。尤其是寫複雜查詢的時候,代碼層次感特別強:

// 命名建議:用 b0、b1 這樣的簡寫表示嵌套層級
SearchResponse<Doc> results = client.search(b0 -> b0
    .index("my-index")
    .query(b1 -> b1
        .bool(b2 -> b2
            .must(b3 -> b3
                .match(b4 -> b4
                    .field("title")
                    .query("搜索")
                )
            )
            .filter(b3 -> b3
                .range(b4 -> b4
                    .field("date")
                    .gte("2024-01-01")
                )
            )
        )
    ),
    Doc.class
);

好了,説回索引管理

啥是索引管理?

簡單來説就是對索引進行增刪改查的一些基本操作。比如:

  • 建個新索引
  • 刪掉不要的索引
  • 關閉/打開某個索引
  • 刷新一下讓數據立馬能搜到
  • 清個緩存
  • 整理一下索引段(讓搜索更快)

新版 SDK 在這塊的設計特別貼心,同步異步都支持,用起來特別順手。

同步方式怎麼用?

上代碼!下面這段代碼基本涵蓋了日常用到的所有索引管理操作:

    String index = "test1";
    // 先看看索引在不在
    if (client.indices().exists(r -> r.index(index)).value()) {
        LOGGER.info("Deleting index " + index);
        // 在的話就刪掉重來
        DeleteIndexResponse deleteIndexResponse =
            client.indices().delete(new DeleteIndexRequest.Builder().index(index).build());
        LOGGER.info(deleteIndexResponse.toString());
    }

    // 建個新的
    LOGGER.info("Creating index " + index);
    CreateIndexResponse createIndexResponse =
        client.indices().create(req -> req.index(index));

    // 關閉索引
    CloseIndexResponse closeIndexResponse =
        client.indices().close(req -> req.index(index));

    // 打開索引
    OpenResponse openResponse =
        client.indices().open(req -> req.index(index));

    // 刷新一下,讓剛寫入的數據馬上能搜到
    RefreshResponse refreshResponse =
        client.indices().refresh(req -> req.index(index));

    // 把內存裏的數據都寫到磁盤上
    FlushResponse flushResponse =
        client.indices().flush(req -> req.index(index));

    // 整理一下索引段,搜索會快很多
    // maxNumSegments(1L) 意思是整理成一個段
    ForcemergeResponse forcemergeResponse =
        client.indices().forcemerge(req -> req.index(index).maxNumSegments(1L));

看代碼就能明白,這些操作都特別直觀,基本上方法名就能告訴你它是幹啥的。而且返回的 Response 對象裏都帶着詳細的執行結果,出了問題很容易排查。

異步方式又是咋回事?

有時候你可能不想等着這些操作一個個完成,這時候就可以用異步方式:


    String index = "test1";
    EasysearchAsyncClient asyncClient = SampleClient.createAsyncClient();

    // 用CompletableFuture串起來一串操作
    asyncClient.indices().exists(req -> req.index(index))
        .thenCompose(exists -> {
            if (exists.value()) {
                LOGGER.info("Deleting index " + index);
                return asyncClient.indices().delete(r -> r.index(index))
                    .thenAccept(deleteResponse -> {
                        LOGGER.info(deleteResponse);
                    });
            }
            return CompletableFuture.completedFuture(null);
        })
        .thenCompose(v -> {
            LOGGER.info("Creating index " + index);
            return asyncClient.indices().create(req -> req.index(index));
        })
        .whenComplete((createResponse, throwable) -> {
            if (throwable != null) {
                LOGGER.error("哎呀出錯了", throwable);
            } else {
                LOGGER.info("搞定!");
            }
        })
        .get(30, TimeUnit.SECONDS); // 最多等30秒

異步方式看起來代碼多了點,但是好處也很明顯:

  1. 不會卡住主線程
  2. 可以併發執行多個操作
  3. 配合 CompletableFuture 能實現很多花樣

小貼士

  1. 選哪種方式?

    • 簡單場景用同步,代碼簡單直觀
    • 要併發或者不想阻塞就用異步
  2. 記得處理異常

    • 同步的就直接 try-catch
    • 異步的用 whenComplete 或 exceptionally 來處理
  3. 性能方面

    • force merge 挺耗資源的,建議半夜執行
    • refresh 太頻繁會影響寫入性能,根據需要權衡

自動翻轉 (Rollover)

在管理 Easysearch 索引時,我們經常需要控制單個索引的大小和時間跨度。Easysearch 的 Rollover API 提供了一個優雅的解決方案,允許我們基於特定條件自動創建新索引。本文將介紹如何使用 Java API 實現索引 rollover。

什麼是 Rollover?

Rollover 是一種索引管理機制,當現有索引滿足一個或多個條件時(如達到一定大小、文檔數量或時間),會自動創建一個新索引。這對於日誌管理等場景特別有用。

實現示例

首先,我們需要創建一個初始索引並設置別名:

String index = "test-00001";
// 如果索引存在則刪除
if (client.indices().exists(r -> r.index(index)).value()) {
    client.indices().delete(new DeleteIndexRequest.Builder().index(index).build());
}

// 創建索引並設置別名
client.indices().create(req -> req
    .index(index)
    .aliases("test_log", a -> a.isWriteIndex(true)));

配置 Rollover 條件

有兩種方式配置 rollover 條件:

方式一:使用 Java API

RolloverResponse res = client.indices().rollover(req -> req
    .alias("test_log")
    .conditions(c -> c
        .maxDocs(100L)        // 文檔數量超過100
        .maxAge(b -> b.time("7d"))  // 索引年齡超過7天
        .maxSize("5gb")));    // 索引大小超過5GB

方式二:使用 JSON 配置

String conditionsJson = """
{
  "conditions": {
    "max_docs": 100,
    "max_age": "7d",
    "max_size": "5gb"
  }
}
""";

RolloverResponse response = client.indices().rollover(req -> req
    .alias("test_log")
    .withJson(new StringReader(conditionsJson))
);

Rollover 條件説明

  • max_docs: 索引中的最大文檔數
  • max_age: 索引最大存在時間
  • max_size: 索引的最大存儲大小

當滿足任一條件時,系統會自動創建新索引。新索引的命名規則是將原索引名稱中的數字部分加 1。


想要了解更多?

  • 客户端 Maven 地址: https://mvnrepository.com/artifact/com.infinilabs/easysearch-client/2.0.2
  • 更詳細的文檔和示例代碼在 官網 持續更新中,請隨時關注!

大家有啥問題或者建議,也歡迎隨時反饋!

關於 Easysearch

INFINI Easysearch 是一個分佈式的搜索型數據庫,實現非結構化數據檢索、全文檢索、向量檢索、地理位置信息查詢、組合索引查詢、多語種支持、聚合分析等。Easysearch 可以完美替代 Elasticsearch,同時添加和完善多項企業級功能。Easysearch 助您擁有簡潔、高效、易用的搜索體驗。

官網文檔:https://infinilabs.cn/docs/latest/easysearch

作者:張磊,極限科技(INFINI Labs)搜索引擎研發負責人,對 Elasticsearch 和 Lucene 源碼比較熟悉,目前主要負責公司的 Easysearch 產品的研發以及客户服務工作。
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.