#126 - Book benchmark for MongoDB similar to the relational ones.

This commit is contained in:
Oliver Drotbohm
2019-08-13 13:15:51 +02:00
parent 757318b5cd
commit d8381cb4fc
6 changed files with 301 additions and 7 deletions

View File

@@ -22,19 +22,20 @@
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
</dependency>
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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<Document> collection;
private Function<Document, Book> mapper;
private ExecutableFind<Book> 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"));
}
}

View File

@@ -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<Book, ObjectId> {
@Query("{ \"title\" : $0 }")
Book findDeclaredByTitle(String title);
Book findDerivedByTitle(String title);
Optional<Book> findOptionalDerivedByTitle(String title);
}

View File

@@ -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 {}
}