Overview
このチュートリアルでは、JavaドライバーとSpring Data MongoDBを使用して、Spring Bootアプリケーションで高パフォーマンスの一括挿入を実行する方法を学ぶことができます。
Spring Data MongoDB
spring Data MongoDB は、 MongoDBの公式spring Dataオブジェクトドキュメントマッパー(ODM)です。POJO(Plain Old Java Object)とリポジトリの抽象化を使用してMongoDBと交流できます。動的クエリ、インデックスの作成、ネストされたドキュメントマッピングなどのMongoDB固有の機能をサポートすると同時に、手動の find() 呼び出しや update() 呼び出しなどの単調なコードを削減します。
プログラムの起動
上に構築されたフレームフレームワークです。自動構成、デフォルト、本番環境に対応する機能が追加され、Spring Data MongoDBとの統合など、SpringベースのJavaアプリケーションの構築が簡素化されます。詳細については、書込み保証 (write concern) のドキュメントを参照してください。
依存関係挿入
依存関係インジェクション(DI)は、Spring フレームワークの主要原則です。これにより、WiredTigerコンテナは操作を使用する他の操作を実行するために、以下の操作を実行します。これは、クラスが使用するオブジェクトの初期化と構築を担当する一般的なオブジェクト指向開発とは異なります。
依存関係インジェクションの詳細については、Springフレームワークのドキュメントの「依存関係インジェクション」ページを参照してください。
spring Data BulkOperations インターフェース
BulkOperations は、データベースに適用できる書き込み (write) 操作のリストを含むSpring Data MongoDBインターフェースです。同様のMongoDB Javaドライバー操作にマップされる次の操作の任意の組み合わせを取り扱うことができます。
insertupdateOneupdateManyreplaceOnedeleteOnedeleteManyupsert
BulkOperation は順序付けまたは順序付けなしで使用できます。順序付き一括操作では操作が順番に実行され、エラーが検出された場合はエラー コードが返されます。順序付けられていない操作は並列で実行されるため、通常はより高速です。ただし、操作中にエラーが発生したかを手動で確認する必要があります。
一括操作の詳細については、次のリソースを参照してください。
Tutorial
このチュートリアルの完了したサンプルアプリは、SpringDataBulkInsert サンプルプロジェクト GitHubリポジトリにあります。
前提条件
このチュートリアルを開始する前に、次のコンポーネントがインストールされ、設定されていることを確認してください。
依存関係を追加する
使用しているMongoDB JavaドライバーおよびJavaバージョンと互換性のあるSpring Data MongoDBバージョンを使用していることを確認してください。互換性の仕様については、spring Data MongoDBドキュメントの要件ページとこのガイドの互換性ページを参照してください。
注意
shell を使用してサンプルをプロジェクトした場合は、バージョン管理の互換性はすでに考慮されており、spring-boot-starter-data-mongodb コンポーネントはすでにpom.xml ファイルに含まれています。
次の依存関係を pom.xmlファイルに追加します。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> <version>3.2.5 </version> </dependency> <dependency> <groupId>net.datafaker</groupId> <artifactId>datafaker</artifactId> <version>2.4.3</version> </dependency>
datafaker 依存関係は、一括書き込み操作で使用する大量の Product オブジェクトを生成するために使用されます。
MongoClient を設定する
MongoConfigクラスには、spring DataフレームワークがMongoDB Serverと交流することを可能にするMongoClientオブジェクトの構成と、その他の構成オプションが設定されています。構成オプションの詳細については、このガイドの「接続オプションの指定」ページを参照してください。
このアプリケーションでは、クラスに @Configuration アノテーション、メソッドに @Bean アノテーション、パラメータ変換に @Value アノテーションを使用します。これらの注釈により、Spring Inversion of Control(IoC)コンテナがオブジェクトをマネージドできるようになります。これらの注釈の詳細については、spring Dataフレームワークガイドの次のセクションを参照してください。
@Configurationおよび@Bean注釈:Java ベースのコンテナ構成@Value注釈: @Value の使用
MongoDB接続を設定するには、MongoConfig.javaファイルを作成し、次の構成クラスとテンプレートクラスを追加します。
public class MongoConfig { private String uri; private String databaseName; public MongoClient mongoClient() { ConnectionString connectionString = new ConnectionString(uri); MongoClientSettings mongoClientSettings = MongoClientSettings.builder() .applyConnectionString(connectionString) .build(); return MongoClients.create(mongoClientSettings); } public MongoTemplate mongoTemplate() throws Exception { return new MongoTemplate(mongoClient(), databaseName); } }
注意
APIとインターフェース
この実装では、MongoRepository などのSpring Dataリポジトリインターフェースを拡張するのではなく、MongoTemplate APIを使用して、一括操作をきめ細やかに制御できるようにします。
application.propertiesファイルに接続文字列(mongodb.uri)、データベース名(mongodb.database)、一括操作数(documentCount)の値を設定します。
mongodb.database=bulk mongodb.uri=<connection string> documentCount=25000
このチュートリアルでは、bulk という名前のデータベースを使用し、保存するために 25、000 ドキュメントを作成します。<connection
string> プレースホルダーを Atlas 配置の接続文字列に置き換えます。詳細については、このガイドの 「接続文字列の作成」セクション を参照してください。
オブジェクトをドキュメントにマッピング
クラスをコレクションにマッピングすると、Spring IoCコンテナはオブジェクトをMongoDBドキュメントとして保存できます。クラスがマッピングされるコレクションを指定するには、@Document アノテーションを使用します。オブジェクトをMongoDBドキュメントにマッピングする方法の詳細については、Spring Data MongoDBドキュメントの「マッピング注釈の概要」セクションを参照してください。
次のコードの @Id 注釈は、オブジェクトidフィールドがドキュメント_idフィールドにマップされることを示します。これはMongoDBドキュメントで一意の識別子として使用されます。配列を除く任意のタイプのフィールドを一意の識別子として選択できます。詳細については、spring Data MongoDBドキュメントの「マッピングレイヤーセクションで_idフィールドがどのように処理されるか」を参照してください。
次のコードを使用して Product.javaファイルを作成し、Productクラスを定義し、それを productsコレクションにマッピングします。
public class Product { private static final Logger LOG = LoggerFactory.getLogger(Product.class); private String id; private String name; private int qty; private double price; private Date available; private Date unavailable; private String skuId; public Product(String name, int qty, double price, Date available, Date unavailable, String skuId) { this.name = name; this.qty = qty; this.price = price; this.available = available; this.unavailable = unavailable; this.skuId = skuId; } public static List<Product> randomProducts(int count) { Faker faker = new Faker(); Random rand = new Random(); List<Product> retProds = new ArrayList<>(count); for (int i = 0; i < count; ++i) { Product product = new Product(faker.animal().name(), 1 + rand.nextInt(998), 10.0 + rand.nextInt(9999), new Date(), new Date(), faker.idNumber().valid()); retProds.add(product); } return retProds; } // Getters and setters }
Productクラスには、Product オブジェクトの配列を生成する静的メソッドが含まれています。フィールドの getter と setter を定義することもできます。
製品を保存するためのリポジトリの定義
ProductRepositoryオブジェクトは Product オブジェクトのコレクションを管理します。ProductRepositoryオブジェクトには、MongoConfigクラスで生成された MongoTemplate beans を使用する必要があります。mongoTemplate を引数として含むコンストラクタで @Autowired アノテーションを使用することで、springコンテナはコンストラクタ インジェクションを使用して mongoTemplate 依存関係を挿入します。コンストラクターインジェクションの詳細については、Spring フレームワーク ドキュメントの「コンストラクターベースの依存関係インジェクション」セクションを参照してください。
次のコードを使用して ProductRepository.javaファイルを作成し、Product オブジェクトのコレクションを管理するための ProductRepositoryクラスを定義します。
public class ProductRepository { private static final Logger LOG = LoggerFactory .getLogger(ProductRepository.class); private final MongoTemplate mongoTemplate; public ProductRepository(MongoTemplate mongoTemplate){ this.mongoTemplate = mongoTemplate; } public void updateProductQuantity(String name, int newQuantity) { Query query = new Query(Criteria.where("name").is(name)); Update update = new Update(); update.set("quantity", newQuantity); UpdateResult result = mongoTemplate.updateFirst(query, update, Product.class); if (result == null) LOG.error("No documents updated"); else LOG.info(result.getModifiedCount() + " document(s) updated.."); } public int bulkInsertProducts(int count) { LOG.info("Dropping collection..."); mongoTemplate.dropCollection(Product.class); LOG.info("Dropped!"); Instant start = Instant.now(); mongoTemplate.setWriteConcern(WriteConcern.W1.withJournal(true)); List<Product> productList = Product.randomProducts(count); BulkOperations bulkInsertion = mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, Product.class); bulkInsertion.insert(productList); BulkWriteResult bulkWriteResult = bulkInsertion.execute(); LOG.info("Bulk insert of " + bulkWriteResult.getInsertedCount() + " documents completed in " + Duration.between(start, Instant.now()).toMillis() + " milliseconds"); return bulkWriteResult.getInsertedCount(); } }
bulkInsertProducts() メソッドは順序なしの一括挿入を使用するため、操作の順序が保証されないことでパフォーマンスを向上させることができます。
一括操作の実行
メインのアプリケーションクラスは、ProductRepository をトリガーして指定された数の Product オブジェクトを生成し、それらをMongoDBデータベースに保存します。@Autowired アノテーションを使用して ProductRepository を挿入し、実装します。
アプリケーションを実行するには、メインクラスに次のコードを追加します。
public class SpringDataBulkInsertApplication implements CommandLineRunner { private int count; private static final Logger LOG = LoggerFactory .getLogger(SpringDataBulkInsertApplication.class); private ProductRepository repository; public static void main(String[] args) { SpringApplication.run(SpringDataBulkInsertApplication.class, args); } public void run(String... args) throws Exception { repository.bulkInsertProducts(count); LOG.info("End run"); System.exit(0); } }
まとめ
Spring Data MongoDB は、MongoDBを操作するための高レベルの抽象化を提供します。自動依存関係インジェクションをサポートすることでアプリケーションアーキテクチャを簡素化し、手動のクライアント構成と複雑なクエリ処理が不要になります。かためのコードの分離を減らし、 オブジェクト指向のデータアクセス をサポートすることで、データアクセスを効率化し、懸念事項を明確に認識できるようになります。
その他のリソース
MongoDB のスケーリングと書込み (write) の詳細については、次のリソースを参照してください。
MongoDB Community のサポートや貢献については、MongoDB Developer Community を参照してください。