From d8381cb4fc6365272ad8bbbbd969aa04e6dc6cb8 Mon Sep 17 00:00:00 2001 From: Oliver Drotbohm Date: Tue, 13 Aug 2019 13:15:51 +0200 Subject: [PATCH] #126 - Book benchmark for MongoDB similar to the relational ones. --- benchmark/mongodb/pom.xml | 15 +- .../data/microbenchmark/mongodb/Book.java | 44 ++++++ .../microbenchmark/mongodb/Constants.java | 27 ++++ .../mongodb/MongoDbBenchmark.java | 132 ++++++++++++++++++ .../mongodb/MongoDbBookRepository.java | 35 +++++ .../mongodb/MongoDbFixture.java | 55 ++++++++ 6 files changed, 301 insertions(+), 7 deletions(-) create mode 100644 benchmark/mongodb/src/main/java/org/springframework/data/microbenchmark/mongodb/Book.java create mode 100644 benchmark/mongodb/src/main/java/org/springframework/data/microbenchmark/mongodb/Constants.java create mode 100644 benchmark/mongodb/src/main/java/org/springframework/data/microbenchmark/mongodb/MongoDbBenchmark.java create mode 100644 benchmark/mongodb/src/main/java/org/springframework/data/microbenchmark/mongodb/MongoDbBookRepository.java create mode 100644 benchmark/mongodb/src/main/java/org/springframework/data/microbenchmark/mongodb/MongoDbFixture.java diff --git a/benchmark/mongodb/pom.xml b/benchmark/mongodb/pom.xml index 837a7c2..659c2d1 100644 --- a/benchmark/mongodb/pom.xml +++ b/benchmark/mongodb/pom.xml @@ -22,19 +22,20 @@ - org.springframework.data - spring-data-commons - - - - org.springframework.data - spring-data-mongodb + org.springframework.boot + spring-boot-starter-data-mongodb org.mockito mockito-core + + + de.flapdoodle.embed + de.flapdoodle.embed.mongo + runtime + diff --git a/benchmark/mongodb/src/main/java/org/springframework/data/microbenchmark/mongodb/Book.java b/benchmark/mongodb/src/main/java/org/springframework/data/microbenchmark/mongodb/Book.java new file mode 100644 index 0000000..62d3cb2 --- /dev/null +++ b/benchmark/mongodb/src/main/java/org/springframework/data/microbenchmark/mongodb/Book.java @@ -0,0 +1,44 @@ +/* + * Copyright 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.microbenchmark.mongodb; + +import org.bson.types.ObjectId; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.PersistenceConstructor; +import org.springframework.data.mongodb.core.mapping.Document; + +import lombok.AllArgsConstructor; +import lombok.Value; + +/** + * @author Oliver Drotbohm + */ +@Value +@Document +@AllArgsConstructor(onConstructor = @__(@PersistenceConstructor)) +public class Book { + + @Id ObjectId id; + String title; + int pages; + + public Book(String title, int pages) { + + this.id = ObjectId.get(); + this.title = title; + this.pages = pages; + } +} diff --git a/benchmark/mongodb/src/main/java/org/springframework/data/microbenchmark/mongodb/Constants.java b/benchmark/mongodb/src/main/java/org/springframework/data/microbenchmark/mongodb/Constants.java new file mode 100644 index 0000000..f1bab73 --- /dev/null +++ b/benchmark/mongodb/src/main/java/org/springframework/data/microbenchmark/mongodb/Constants.java @@ -0,0 +1,27 @@ +/* + * Copyright 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.microbenchmark.mongodb; + +import lombok.experimental.UtilityClass; + +/** + * @author Oliver Drotbohm + */ +@UtilityClass +class Constants { + + public static final int NUMBER_OF_BOOKS = 8; +} diff --git a/benchmark/mongodb/src/main/java/org/springframework/data/microbenchmark/mongodb/MongoDbBenchmark.java b/benchmark/mongodb/src/main/java/org/springframework/data/microbenchmark/mongodb/MongoDbBenchmark.java new file mode 100644 index 0000000..ef2db16 --- /dev/null +++ b/benchmark/mongodb/src/main/java/org/springframework/data/microbenchmark/mongodb/MongoDbBenchmark.java @@ -0,0 +1,132 @@ +/* + * Copyright 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.microbenchmark.mongodb; + +import java.util.ArrayList; + +import org.bson.Document; +import org.bson.conversions.Bson; +import org.bson.types.ObjectId; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.infra.Blackhole; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.data.microbenchmark.common.AbstractMicrobenchmark; +import org.springframework.data.mongodb.core.ExecutableFindOperation.ExecutableFind; +import org.springframework.data.mongodb.core.MongoOperations; +import org.springframework.data.mongodb.core.convert.MappingMongoConverter; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; + +import com.mongodb.Function; +import com.mongodb.client.MongoCollection; + +/** + * @author Oliver Drotbohm + */ +public class MongoDbBenchmark extends AbstractMicrobenchmark { + + private static final Query BY_TITLE = Query.query(Criteria.where("title").is("title0")); + + private MongoCollection collection; + private Function mapper; + + private ExecutableFind findBook; + private MongoDbBookRepository repository; + + private MappingMongoConverter converter; + private Bson bookSource; + + @Setup + public void setUp() { + + ConfigurableApplicationContext context = new MongoDbFixture().getContext(); + + MongoOperations operations = context // + .getBean(MongoOperations.class); + + this.collection = operations.getCollection(operations.getCollectionName(Book.class)); + this.mapper = document -> new Book(document.getObjectId("_id"), document.getString("title"), document.getInteger("pages")); + + this.findBook = operations // + .query(Book.class); + + this.repository = context // + .getBean(MongoDbBookRepository.class); + + this.converter = context // + .getBean(MappingMongoConverter.class); + + this.bookSource = new Document("title", "title1") // + .append("pages", 42) // + .append("_id", ObjectId.get()); + } + + @Benchmark + public void convertSingleBook(Blackhole sink) { + sink.consume(converter.read(Book.class, bookSource)); + } + + @Benchmark + public void rawFindAll(Blackhole sink) { + sink.consume(collection.find().map(mapper).into(new ArrayList<>())); + } + + @Benchmark + public void findAll(Blackhole sink) { + sink.consume(findBook.all()); + } + + @Benchmark + public void repositoryFindAll(Blackhole sink) { + sink.consume(repository.findAll()); + } + + @Benchmark + public void rawFindByTitle(Blackhole sink) { + + sink.consume(collection.find() // + .filter(new Document("title", "title0")) // + .map(mapper) // + .first()); + } + + @Benchmark + public void findByTitle(Blackhole sink) { + sink.consume(findBook.matching(BY_TITLE).firstValue()); + } + + @Benchmark + public void repositoryFindByTitle(Blackhole sink) { + sink.consume(repository.findDerivedByTitle("title0")); + } + + @Benchmark + public void findByTitleOptional(Blackhole sink) { + sink.consume(findBook.matching(BY_TITLE).first()); + } + + @Benchmark + public void repositoryFindByTitleOptional(Blackhole sink) { + sink.consume(repository.findOptionalDerivedByTitle("title0")); + } + + + @Benchmark + public void repositoryFindByTitleDeclared(Blackhole sink) { + sink.consume(repository.findDeclaredByTitle("title0")); + } +} diff --git a/benchmark/mongodb/src/main/java/org/springframework/data/microbenchmark/mongodb/MongoDbBookRepository.java b/benchmark/mongodb/src/main/java/org/springframework/data/microbenchmark/mongodb/MongoDbBookRepository.java new file mode 100644 index 0000000..3202ce1 --- /dev/null +++ b/benchmark/mongodb/src/main/java/org/springframework/data/microbenchmark/mongodb/MongoDbBookRepository.java @@ -0,0 +1,35 @@ +/* + * Copyright 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.microbenchmark.mongodb; + +import java.util.Optional; + +import org.bson.types.ObjectId; +import org.springframework.data.mongodb.repository.Query; +import org.springframework.data.repository.CrudRepository; + +/** + * @author Oliver Drotbohm + */ +interface MongoDbBookRepository extends CrudRepository { + + @Query("{ \"title\" : $0 }") + Book findDeclaredByTitle(String title); + + Book findDerivedByTitle(String title); + + Optional findOptionalDerivedByTitle(String title); +} diff --git a/benchmark/mongodb/src/main/java/org/springframework/data/microbenchmark/mongodb/MongoDbFixture.java b/benchmark/mongodb/src/main/java/org/springframework/data/microbenchmark/mongodb/MongoDbFixture.java new file mode 100644 index 0000000..241e375 --- /dev/null +++ b/benchmark/mongodb/src/main/java/org/springframework/data/microbenchmark/mongodb/MongoDbFixture.java @@ -0,0 +1,55 @@ +/* + * Copyright 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.microbenchmark.mongodb; + +import java.util.Collections; +import java.util.stream.IntStream; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.data.mongodb.core.MongoOperations; + +import lombok.Getter; + +/** + * @author Oliver Drotbohm + */ +class MongoDbFixture { + + private final @Getter ConfigurableApplicationContext context; + + MongoDbFixture() { + + SpringApplication application = new SpringApplication(); + application.addPrimarySources(Collections.singletonList(MongoDbApplication.class)); + application.setAdditionalProfiles("jpa"); + application.setLazyInitialization(true); + + this.context = application.run(); + + MongoOperations operations = context.getBean(MongoOperations.class); + + operations.dropCollection(Book.class); + + IntStream.range(0, Constants.NUMBER_OF_BOOKS) // + .mapToObj(it -> new Book("title" + it, it)) // + .forEach(operations::save); + } + + @SpringBootApplication + static class MongoDbApplication {} +}