-
-
Save danielmitterdorfer/6f78acbd5edc9e9371d94e4ae45fffb7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Licensed to Elasticsearch under one or more contributor | |
* license agreements. See the NOTICE file distributed with | |
* this work for additional information regarding copyright | |
* ownership. Elasticsearch licenses this file to you 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 | |
* | |
* http://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.elasticsearch.benchmark.parser; | |
import org.elasticsearch.common.bytes.BytesReference; | |
import org.elasticsearch.common.xcontent.XContentParser; | |
import org.elasticsearch.common.xcontent.XContentType; | |
import org.elasticsearch.search.suggest.completion.CompletionSuggestion; | |
import org.openjdk.jmh.annotations.Benchmark; | |
import org.openjdk.jmh.annotations.BenchmarkMode; | |
import org.openjdk.jmh.annotations.Fork; | |
import org.openjdk.jmh.annotations.Measurement; | |
import org.openjdk.jmh.annotations.Mode; | |
import org.openjdk.jmh.annotations.OutputTimeUnit; | |
import org.openjdk.jmh.annotations.Param; | |
import org.openjdk.jmh.annotations.Scope; | |
import org.openjdk.jmh.annotations.Setup; | |
import org.openjdk.jmh.annotations.State; | |
import org.openjdk.jmh.annotations.Warmup; | |
import java.io.IOException; | |
import java.net.URISyntaxException; | |
import java.security.NoSuchAlgorithmException; | |
import java.util.concurrent.TimeUnit; | |
import static org.elasticsearch.common.xcontent.XContentHelper.toXContent; | |
@Fork(3) | |
@Warmup(iterations = 10) | |
@Measurement(iterations = 10) | |
@BenchmarkMode(Mode.AverageTime) | |
@OutputTimeUnit(TimeUnit.MICROSECONDS) | |
@State(Scope.Benchmark) | |
@SuppressWarnings("unused") //invoked by benchmarking framework | |
public class ParserBenchmark { | |
private XContentType xContentType; | |
private BytesReference originalBytes; | |
private XContentParser parser; | |
@Param(value = {"false", "true"}) | |
private String humanReadable; | |
@Param(value = {"JSON", "SMILE", "YAML", "CBOR"}) | |
private String contentType; | |
@Setup | |
public void setUp() throws IOException, NoSuchAlgorithmException, URISyntaxException { | |
CompletionSuggestion.Entry.Option option = ParserBenchmarkHelper.createTestItem(); | |
xContentType = XContentType.valueOf(contentType); | |
originalBytes = toXContent(option, xContentType, Boolean.valueOf(humanReadable)); | |
} | |
@Benchmark | |
public CompletionSuggestion.Entry.Option parse() throws Exception { | |
try (XContentParser p = ParserBenchmarkHelper.parser(xContentType.xContent(), originalBytes)) { | |
return CompletionSuggestion.Entry.Option.fromXContent(p); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Licensed to Elasticsearch under one or more contributor | |
* license agreements. See the NOTICE file distributed with | |
* this work for additional information regarding copyright | |
* ownership. Elasticsearch licenses this file to you 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 | |
* | |
* http://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.elasticsearch.benchmark.parser; | |
import com.carrotsearch.randomizedtesting.generators.RandomNumbers; | |
import com.carrotsearch.randomizedtesting.generators.RandomPicks; | |
import com.carrotsearch.randomizedtesting.generators.RandomStrings; | |
import org.apache.lucene.search.Explanation; | |
import org.elasticsearch.cluster.ClusterModule; | |
import org.elasticsearch.common.bytes.BytesReference; | |
import org.elasticsearch.common.collect.Tuple; | |
import org.elasticsearch.common.text.Text; | |
import org.elasticsearch.common.xcontent.NamedXContentRegistry; | |
import org.elasticsearch.common.xcontent.XContent; | |
import org.elasticsearch.common.xcontent.XContentParser; | |
import org.elasticsearch.common.xcontent.XContentType; | |
import org.elasticsearch.index.Index; | |
import org.elasticsearch.index.shard.ShardId; | |
import org.elasticsearch.search.SearchHit; | |
import org.elasticsearch.search.SearchHitField; | |
import org.elasticsearch.search.SearchShardTarget; | |
import org.elasticsearch.search.SearchSortValues; | |
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField; | |
import org.elasticsearch.search.suggest.completion.CompletionSuggestion; | |
import org.elasticsearch.test.RandomObjects; | |
import java.io.IOException; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.HashMap; | |
import java.util.HashSet; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.Random; | |
import java.util.Set; | |
import java.util.function.Supplier; | |
public class ParserBenchmarkHelper { | |
private static List<String> META_FIELDS = Arrays.asList("_uid", "_all", "_parent", "_routing", "_size", "_timestamp", "_ttl"); | |
private static NamedXContentRegistry XCONTENT_REGISTRY = new NamedXContentRegistry(ClusterModule.getNamedXWriteables()); | |
public static boolean randomBoolean() { | |
return getRandom().nextBoolean(); | |
} | |
public static byte randomByte() { | |
return (byte) getRandom().nextInt(); | |
} | |
public static short randomShort() { | |
return (short) getRandom().nextInt(); | |
} | |
public static int randomInt() { | |
return getRandom().nextInt(); | |
} | |
public static int randomInt(int max) { | |
return RandomNumbers.randomIntBetween(getRandom(), 0, max); | |
} | |
public static float randomFloat() { | |
return getRandom().nextFloat(); | |
} | |
public static double randomDouble() { | |
return getRandom().nextDouble(); | |
} | |
public static long randomLong() { | |
return getRandom().nextLong(); | |
} | |
public static String randomAsciiOfLength(int codeUnits) { | |
return RandomStrings.randomAsciiOfLength(getRandom(), codeUnits); | |
} | |
/** | |
* Pick a random object from the given array. The array must not be empty. | |
*/ | |
public static <T> T randomFrom(T... array) { | |
return randomFrom(getRandom(), array); | |
} | |
/** | |
* Pick a random object from the given array. The array must not be empty. | |
*/ | |
public static <T> T randomFrom(Random random, T... array) { | |
return RandomPicks.randomFrom(random, array); | |
} | |
/** | |
* Pick a random object from the given list. | |
*/ | |
public static <T> T randomFrom(List<T> list) { | |
return RandomPicks.randomFrom(getRandom(), list); | |
} | |
// /** Pick a random object from the given collection. */ | |
// public static <T> T randomFrom(Collection<T> collection) { | |
// return randomFrom(getRandom(), collection); | |
// } | |
public static boolean rarely() { | |
return randomInt(100) >= 90; | |
} | |
/** | |
* The exact opposite of {@link #rarely()}. | |
*/ | |
public static boolean frequently() { | |
return !rarely(); | |
} | |
public static int randomIntBetween(int min, int max) { | |
return RandomNumbers.randomIntBetween(getRandom(), min, max); | |
} | |
public static String randomAsciiOfLengthBetween(int minCodeUnits, int maxCodeUnits) { | |
return RandomStrings.randomAsciiOfLengthBetween(getRandom(), minCodeUnits, maxCodeUnits); | |
} | |
public static String randomRealisticUnicodeOfCodepointLengthBetween(int minCodePoints, int maxCodePoints) { | |
return RandomStrings.randomRealisticUnicodeOfCodepointLengthBetween(getRandom(), minCodePoints, maxCodePoints); | |
} | |
public static String randomRealisticUnicodeOfCodepointLength(int codePoints) { | |
return RandomStrings.randomRealisticUnicodeOfCodepointLength(getRandom(), codePoints); | |
} | |
public static HighlightField createHighlightField() { | |
String name = frequently() ? randomAsciiOfLengthBetween(5, 20) : randomRealisticUnicodeOfCodepointLengthBetween(5, 20); | |
Text[] fragments = null; | |
if (frequently()) { | |
int size = randomIntBetween(0, 5); | |
fragments = new Text[size]; | |
for (int i = 0; i < size; i++) { | |
fragments[i] = new Text(frequently() ? randomAsciiOfLengthBetween(10, 30) : randomRealisticUnicodeOfCodepointLengthBetween(10, 30)); | |
} | |
} | |
return new HighlightField(name, fragments); | |
} | |
public static SearchHit.NestedIdentity createNestedIdentity(int depth) { | |
String field = frequently() ? randomAsciiOfLengthBetween(1, 20) : randomRealisticUnicodeOfCodepointLengthBetween(1, 20); | |
int offset = randomInt(10); | |
SearchHit.NestedIdentity child = null; | |
if (depth > 0) { | |
child = createNestedIdentity(depth - 1); | |
} | |
return new SearchHit.NestedIdentity(field, offset, child); | |
} | |
public static SearchSortValues createSearchSortValues() { | |
List<Supplier<Object>> valueSuppliers = new ArrayList<>(); | |
// this should reflect all values that are allowed to go through the transport layer | |
valueSuppliers.add(() -> null); | |
valueSuppliers.add(() -> randomInt()); | |
valueSuppliers.add(() -> randomLong()); | |
valueSuppliers.add(() -> randomDouble()); | |
valueSuppliers.add(() -> randomFloat()); | |
valueSuppliers.add(() -> randomByte()); | |
valueSuppliers.add(() -> randomShort()); | |
valueSuppliers.add(() -> randomBoolean()); | |
valueSuppliers.add(() -> frequently() ? randomAsciiOfLengthBetween(1, 30) : randomRealisticUnicodeOfCodepointLength(30)); | |
int size = randomIntBetween(1, 20); | |
Object[] values = new Object[size]; | |
for (int i = 0; i < size; i++) { | |
Supplier<Object> supplier = randomFrom(valueSuppliers); | |
values[i] = supplier.get(); | |
} | |
return new SearchSortValues(values); | |
} | |
private static Explanation createExplanation(int depth) { | |
String description = randomAsciiOfLengthBetween(5, 20); | |
float value = randomFloat(); | |
List<Explanation> details = new ArrayList<>(); | |
if (depth > 0) { | |
int numberOfDetails = randomIntBetween(1, 3); | |
for (int i = 0; i < numberOfDetails; i++) { | |
details.add(createExplanation(depth - 1)); | |
} | |
} | |
return Explanation.match(value, description, details); | |
} | |
public static SearchHit createSearchHit(boolean withOptionalInnerHits) { | |
int internalId = randomInt(); | |
String uid = randomAsciiOfLength(10); | |
Text type = new Text(randomAsciiOfLengthBetween(5, 10)); | |
SearchHit.NestedIdentity nestedIdentity = null; | |
if (randomBoolean()) { | |
nestedIdentity = createNestedIdentity(randomIntBetween(0, 2)); | |
} | |
Map<String, SearchHitField> fields = new HashMap<>(); | |
if (randomBoolean()) { | |
int size = randomIntBetween(0, 10); | |
for (int i = 0; i < size; i++) { | |
Tuple<List<Object>, List<Object>> values = RandomObjects.randomStoredFieldValues(getRandom(), XContentType.JSON); | |
if (randomBoolean()) { | |
String metaField = randomFrom(META_FIELDS); | |
fields.put(metaField, new SearchHitField(metaField, values.v1())); | |
} else { | |
String fieldName = randomAsciiOfLengthBetween(5, 10); | |
fields.put(fieldName, new SearchHitField(fieldName, values.v1())); | |
} | |
} | |
} | |
SearchHit hit = new SearchHit(internalId, uid, type, nestedIdentity, fields); | |
if (frequently()) { | |
if (rarely()) { | |
hit.score(Float.NaN); | |
} else { | |
hit.score(randomFloat()); | |
} | |
} | |
if (frequently()) { | |
hit.sourceRef(RandomObjects.randomSource(getRandom())); | |
} | |
if (randomBoolean()) { | |
hit.version(randomLong()); | |
} | |
if (randomBoolean()) { | |
hit.sortValues(createSearchSortValues()); | |
} | |
if (randomBoolean()) { | |
int size = randomIntBetween(0, 5); | |
Map<String, HighlightField> highlightFields = new HashMap<>(size); | |
for (int i = 0; i < size; i++) { | |
highlightFields.put(randomAsciiOfLength(5), createHighlightField()); | |
} | |
hit.highlightFields(highlightFields); | |
} | |
if (randomBoolean()) { | |
int size = randomIntBetween(0, 5); | |
String[] matchedQueries = new String[size]; | |
for (int i = 0; i < size; i++) { | |
matchedQueries[i] = randomAsciiOfLength(5); | |
} | |
hit.matchedQueries(matchedQueries); | |
} | |
if (randomBoolean()) { | |
hit.explanation(createExplanation(randomIntBetween(0, 5))); | |
} | |
if (randomBoolean()) { | |
hit.shard(new SearchShardTarget(randomAsciiOfLengthBetween(5, 10), new ShardId(new Index(randomAsciiOfLengthBetween(5, 10), randomAsciiOfLengthBetween(5, 10)), randomInt()))); | |
} | |
return hit; | |
} | |
public static CompletionSuggestion.Entry.Option createTestItem() { | |
Text text = new Text(randomAsciiOfLengthBetween(5, 15)); | |
int docId = randomInt(); | |
int numberOfContexts = randomIntBetween(0, 3); | |
Map<String, Set<CharSequence>> contexts = new HashMap<>(); | |
for (int i = 0; i < numberOfContexts; i++) { | |
int numberOfValues = randomIntBetween(0, 3); | |
Set<CharSequence> values = new HashSet<>(); | |
for (int v = 0; v < numberOfValues; v++) { | |
values.add(randomAsciiOfLengthBetween(5, 15)); | |
} | |
contexts.put(randomAsciiOfLengthBetween(5, 15), values); | |
} | |
SearchHit hit = null; | |
float score = randomFloat(); | |
if (randomBoolean()) { | |
hit = createSearchHit(false); | |
score = hit.getScore(); | |
} | |
CompletionSuggestion.Entry.Option option = new CompletionSuggestion.Entry.Option(docId, text, score, contexts); | |
option.setHit(hit); | |
return option; | |
} | |
public static XContentParser parser(XContent xContent, BytesReference originalBytes) throws IOException { | |
return xContent.createParser(XCONTENT_REGISTRY, originalBytes); | |
} | |
public static Random getRandom() { | |
// use a constant seed intentionally to ensure we have more control over the results! | |
return new Random(17L); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment