LoginSignup
0
0

More than 3 years have passed since last update.

Elasticsearch > kotlin > es-kotlin-clinent マニュアル(意訳)3 - indexRepository

Last updated at Posted at 2021-01-23

Elasticsearchをサーバーサイドで操作するKotlin版ライブラリ
がよく出来ていたのでその動作確認をしつつマニュアルを日本語にしつつメモしています。

全10回です。

es-kotlin-clinent マニュアル(意訳)1 - 序章
es-kotlin-clinent マニュアル(意訳)2 - Getting Started
es-kotlin-clinent マニュアル(意訳)3 - indexRepository <- ここ
es-kotlin-clinent マニュアル(意訳)4 - CRUD 操作
es-kotlin-clinent マニュアル(意訳)5 - 楽観的ロック
es-kotlin-clinent マニュアル(意訳)6 - 検索
es-kotlin-clinent マニュアル(意訳)7 - Kotlin Query DSL
es-kotlin-clinent マニュアル(意訳)8 - Asynchronous
es-kotlin-clinent マニュアル(意訳)9 - DSLs
es-kotlin-clinent マニュアル(意訳)10 - Example

2. indexRepositoryの作成

Elasticsearch を使って何かをするためには、ドキュメントを何らかのインデックスに格納しなければならない。

Java クライアントはこれを行うために必要なものをすべて提供しているが、これを正しい方法で使用するには、何を行う必要があるのかを深く理解するだけでなく、かなりのボイラープレートが必要となる。

このライブラリes-kotlin-clinentの重要な部分は、ユーザーフレンドリーな抽象化を提供することです。

SpringRuby on Railsなどの最新のフレームワークを使ってデータベースアプリケーションを書いたことがある人には馴染みのある機能です。

このようなフレームワークでは、リポジトリは特定のデータベーステーブル内のオブジェクトと対話するためのプリミティブを提供します。

es-kotlin-clinentでは同様の抽象化としてIndexRepositoryを提供しています。
インデックスごとにIndexRepositoryを作成することで、作成、読み込み、更新、削除、等のCRUD操作や他のいくつかの操作を行うことができます。

ElasticsearchはJsonドキュメントを格納しているので、Kotlin側でデータクラスを使って表現し、シリアライズ/デシリアライズはIndexRepositoryに任せます。

indexRepositoryの作成

データクラス

いくつかのフィールドを持つシンプルなデータクラスを使ってみましょう。

data class Thing(val name: String, val amount: Long = 42)

IndexRepositoryを作成

indexRepository拡張関数を使用して、Thing用のIndexRepositoryを作成することができます。

// we pass in the index name
val repo = esClient.indexRepository<Thing>("things")

インデックスを作成

オブジェクトを保存する前に、インデックスを作成する必要があります。
これはオプション扱いですが、スキーマレスモードでElasticsearchを使用することはおそらくあなたが望むものではないことに注意してください。
ここではシンプルなマッピングを使用しています。

repo.createIndex {
  // use our friendly DSL to configure the index
  configure {
    settings {
      replicas = 0
      shards = 1
    }
    mappings {
      // in the block you receive FieldMappings as this
      // a simple text field "title": {"type":"text"}
      text("name")
      // a numeric field with sub fields, use generics
      // to indicate what kind of number
      number<Long>("amount") {
        // we can customize the FieldMapping object
        // that we receive in the block
        fields {
          // we get another FieldMappings
          // lets add a keyword field
          keyword("somesubfield")
          // if you want, you can manipulate the
          // FieldMapping as a map
          // this is great for accessing features
          // not covered by our Kotlin DSL
          this["imadouble"] = mapOf("type" to "double")
          number<Double>("abetterway")
        }
      }
    }
  }
}

結果の確認

// stringify is a useful extension function we added to the response
println(repository.getSettings().stringify(true))

repository.getMappings().mappings()
    .forEach { (name, meta) ->
        print("$name -> ${meta.source().string()}")
    }

結果確認:キャプチャされた出力

{
  "test-6a263b18-11de-4d88-b5d3-fc7bc52aaeab" : {
  "settings" : {
    "index" : {
    "creation_date" : "1609078953070",
    "number_of_shards" : "1",
    "number_of_replicas" : "0",
    "uuid" : "C-ZY_-KIRjGdpoju5IkiAw",
    "version" : {
      "created" : "7100099"
    },
    "provided_name" : "test-6a263b18-11de-4d88-b5d3-fc7bc52aaeab"
    }
  }
  }
}
test-6a263b18-11de-4d88-b5d3-fc7bc52aaeab -> {"_meta":{"content_hash":"ZLExK0PCG
9+CpgXySXotIQ==","timestamp":"2020-12-27T14:22:33.052411Z"},"properties":{"amoun
t":{"type":"long","fields":{"abetterway":{"type":"double"},"imadouble":{"type":"
double"},"somesubfield":{"type":"keyword"}}},"name":{"type":"text"}}}

jsonファイルを使ってのインデックス作成

設定用のjsonを使って設定することもできます。
これは、マッピングを別のjsonファイルとして管理している場合に便利です。

// delete the previous version of our index
repo.deleteIndex()
// create a new one using json source
repo.createIndex {
  source(
    """
      {
        "settings": {
        "index": {
          "number_of_shards": 3,
          "number_of_replicas": 0,
          "blocks": {
          "read_only_allow_delete": "false"
          }
        }
        },
        "mappings": {
        "properties": {
          "name": {
          "type": "text"
          },
          "amount": {
          "type": "long"
          }
        }
        }
      }
    """
  )
}

結果確認:キャプチャされた出力

{"things":{"mappings":{"properties":{"amount":{"type":"long"},"name":{"type":"text"}}}}}

カスタムシリアル化

デフォルトでは、人気のあるJacksonフレームワークを使用します。
ただし、他のものが必要な場合は、シリアル化と逆シリアル化の動作をカスタマイズできます。これを行うには、ModelReaderAndWriterの実装を渡すことができます。

デフォルト値は付属のJacksonModelReaderAndWriterのインスタンスで、ThingオブジェクトのシリアライズとデシリアライズにJacksonを使用しています。

デフォルトのJacksonベースのシリアライズが不要な場合や、Jacksonオブジェクトマッパーをカスタマイズしたい場合は、独自のインスタンスを作成してIndexRepositoryに渡すだけです。

// this is what is used by default but you can use your own implementation
val modelReaderAndWriter = JacksonModelReaderAndWriter(
  Thing::class,
  ObjectMapper().findAndRegisterModules()
)

val thingRepository = esClient.indexRepository<Thing>(
  index = "things", modelReaderAndWriter = modelReaderAndWriter
)

Co-routine サポート

このライブラリのほとんどと同じ機能が、コルーチンに適したAsyncIndexRepositoryでも利用できます。

バリアントでも利用できますAsyncIndexRepository。これを使用するには、esClient.asyncIndexRepositoryを使用する必要があります

これは、すべての関数がAsyncIndexRepositoryクラスでsuspendとしてマークされていることを除いて、同期版とほぼ同じように機能します。
さらに、検索メソッドの戻り値の型は異なり、Flow APIを利用します。

ES Kotlinクライアントでコルーチンを使用する方法の詳細については、コルーチンを使用した非同期IOを参照してください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0