Copilot commented on code in PR #16858: URL: https://github.com/apache/lucene/pull/16858#discussion_r4317431950
########## lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/AddJoinDocsTask.java: ########## @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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.apache.lucene.benchmark.byTask.tasks; + +import java.util.List; +import org.apache.lucene.benchmark.byTask.PerfRunData; +import org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker; +import org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.Dataset; Review Comment: This import appears unused in the compiled code (it’s only referenced from Javadoc). If unused imports are enforced, remove it and use `{@link org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.Dataset}` in the Javadoc instead. ########## lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/JoinIndices.java: ########## @@ -0,0 +1,176 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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.apache.lucene.benchmark.byTask.tasks; + +import java.io.Closeable; +import java.io.IOException; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; +import org.apache.lucene.benchmark.byTask.PerfRunData; +import org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker; +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.IndexWriter; +import org.apache.lucene.index.IndexWriterConfig; +import org.apache.lucene.index.IndexWriterConfig.OpenMode; +import org.apache.lucene.index.MultiDocValues; +import org.apache.lucene.index.OrdinalMap; +import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.SearcherFactory; +import org.apache.lucene.search.SearcherManager; +import org.apache.lucene.store.Directory; +import org.apache.lucene.store.FSDirectory; +import org.apache.lucene.util.IOUtils; +import org.apache.lucene.util.NamedThreadFactory; + +/** + * Writers and NRT searchers over the join indices at <b>join.dir</b>/{layout}/index (Default: + * work/join), shared by join tasks and closed with {@link PerfRunData}. Updates are never + * committed, so the indices stay intact for the next run. + * + * <p><b>join.searchThreads</b> - size of the executor shared by all searchers, i.e. segment + * parallel search on both join sides. Fixed per run, since searchers are only recreated on refresh. + * Default: 0, search segments sequentially. + */ +final class JoinIndices implements Closeable { + + /** + * Searcher that carries the global ordinals of {@link JoinDocMaker#FK} for the mixed index. They + * are built by the first query on each new searcher, so a cold search after refresh pays for + * them. + */ + static final class JoinSearcher extends IndexSearcher { + private final boolean ordinals; + private OrdinalMap ordinalMap; + private boolean built; + + JoinSearcher(IndexReader reader, Executor executor, boolean ordinals) { + super(reader, executor); + this.ordinals = ordinals; + } + + synchronized OrdinalMap ordinalMap() throws IOException { + if (ordinals && !built) { + if (MultiDocValues.getSortedValues(getIndexReader(), JoinDocMaker.FK) + instanceof MultiDocValues.MultiSortedDocValues multi) { + ordinalMap = multi.mapping; // a single segment needs no ordinal map + } + built = true; + } + return ordinalMap; + } + } + + record Index(Directory dir, IndexWriter writer, SearcherManager manager) {} + + private final Path root; + private final ExecutorService executor; + private final Map<String, Index> indices = new HashMap<>(); + + private JoinIndices(Path root, int searchThreads) { + this.root = root; + ThreadFactory named = new NamedThreadFactory("join-search"); + // daemon, since Benchmark never closes PerfRunData, and the pool must not keep the JVM alive + executor = + searchThreads > 0 + ? Executors.newFixedThreadPool( + searchThreads, + r -> { + Thread thread = named.newThread(r); + thread.setDaemon(true); + return thread; + }) + : null; + } + + static JoinIndices get(PerfRunData runData) { + synchronized (runData) { + JoinIndices indices = (JoinIndices) runData.getPerfObject(JoinIndices.class.getName()); + if (indices == null) { + indices = + new JoinIndices( + Path.of(runData.getConfig().get("join.dir", "work/join")), + runData.getConfig().get("join.searchThreads", 0)); + runData.setPerfObject(JoinIndices.class.getName(), indices); + } + return indices; + } + } + + synchronized Index index(String layout) throws IOException { + Index index = indices.get(layout); + if (index == null) { + Directory dir = FSDirectory.open(root.resolve(layout).resolve("index")); + IndexWriter writer = + new IndexWriter( + dir, new IndexWriterConfig().setOpenMode(OpenMode.APPEND).setCommitOnClose(false)); Review Comment: `IndexWriterConfig` typically requires an `Analyzer` (no-arg construction is not available in many Lucene versions). This is likely a compile-time failure or an unintended default. Please construct `IndexWriterConfig` with an explicit analyzer (e.g., a keyword analyzer is sufficient for these docs), or reuse the benchmark’s configured analyzer if that’s the intended behavior. ########## lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/JoinSearchTask.java: ########## @@ -0,0 +1,173 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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.apache.lucene.benchmark.byTask.tasks; + +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.BRAND; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.BRANDS; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.COLOR; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.COLORS; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.FK; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.FK_NUM; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.ID; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.ID_NUM; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.PRODUCT; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.SIZE; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.SIZES; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.TYPE; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.value; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.TreeSet; +import org.apache.lucene.benchmark.byTask.PerfRunData; +import org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker; +import org.apache.lucene.index.SortedDocValues; Review Comment: These imports appear unused by the compiled code (references are in Javadocs, and `JoinDocMaker` is already referenced via static imports). If your style/lint setup flags unused imports, remove them and (if needed) fully-qualify Javadoc links. ########## lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/JoinIndices.java: ########## @@ -0,0 +1,176 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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.apache.lucene.benchmark.byTask.tasks; + +import java.io.Closeable; +import java.io.IOException; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; +import org.apache.lucene.benchmark.byTask.PerfRunData; +import org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker; +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.IndexWriter; +import org.apache.lucene.index.IndexWriterConfig; +import org.apache.lucene.index.IndexWriterConfig.OpenMode; +import org.apache.lucene.index.MultiDocValues; +import org.apache.lucene.index.OrdinalMap; +import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.SearcherFactory; +import org.apache.lucene.search.SearcherManager; +import org.apache.lucene.store.Directory; +import org.apache.lucene.store.FSDirectory; +import org.apache.lucene.util.IOUtils; Review Comment: This import appears unused in the current file. In Lucene builds, unused imports are commonly enforced by formatting/checkstyle; please remove it to avoid CI failures. ########## lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/JoinUpdateTask.java: ########## @@ -0,0 +1,162 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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.apache.lucene.benchmark.byTask.tasks; + +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.ID; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.PID; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.productId; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.skuId; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import org.apache.lucene.benchmark.byTask.PerfRunData; +import org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker; Review Comment: This import appears unused in the compiled code (only referenced in Javadoc, and constants are imported statically). Consider removing it and fully qualifying Javadoc references if necessary, to avoid unused-import checks failing. ########## lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/JoinSearchTask.java: ########## @@ -0,0 +1,173 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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.apache.lucene.benchmark.byTask.tasks; + +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.BRAND; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.BRANDS; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.COLOR; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.COLORS; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.FK; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.FK_NUM; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.ID; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.ID_NUM; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.PRODUCT; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.SIZE; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.SIZES; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.TYPE; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.value; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.TreeSet; +import org.apache.lucene.benchmark.byTask.PerfRunData; +import org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker; +import org.apache.lucene.index.SortedDocValues; +import org.apache.lucene.index.Term; +import org.apache.lucene.search.BooleanClause.Occur; +import org.apache.lucene.search.BooleanQuery; +import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.SearcherManager; +import org.apache.lucene.search.TermInSetQuery; +import org.apache.lucene.search.TermQuery; +import org.apache.lucene.search.join.BitSetProducer; +import org.apache.lucene.search.join.JoinUtil; +import org.apache.lucene.search.join.QueryBitSetProducer; +import org.apache.lucene.search.join.ScoreMode; +import org.apache.lucene.search.join.ToParentBlockJoinQuery; +import org.apache.lucene.util.BytesRef; + +/** + * Counts products joined from skus, over the indices written by {@link JoinDocMaker} (see + * conf/join-index.alg). Each query selects skus by a few colors or a few sizes, joins them to their + * products and filters products by a few brands. Every instance draws the same query sequence from + * <b>join.seed</b>, so instances with different algorithms are comparable. + * + * <p>The parameter is the algorithm: + * + * <ul> + * <li><b>term</b> - skus' {@link SortedDocValues} FK to products' PK terms (products, skus) + * <li><b>numeric</b> - skus' {@link org.apache.lucene.index.NumericDocValues} FK to products' PK + * points (products, skus) + * <li><b>globalOrd</b> - global ordinals over {@link SortedDocValues} FK (mixed) + * <li><b>block</b> - {@link ToParentBlockJoinQuery} (block) + * </ul> + * + * <p>Other config properties: <b>join.dir</b> and <b>join.searchThreads</b>, see {@link + * JoinIndices}; <b>join.scoreMode</b> - Default: None. + */ +public class JoinSearchTask extends PerfTask { + + private static final BitSetProducer PRODUCTS = + new QueryBitSetProducer(new TermQuery(new Term(TYPE, PRODUCT))); + + private final Random random; + private final ScoreMode scoreMode; + private String algorithm; + private SearcherManager fromManager; + private SearcherManager toManager; + private IndexSearcher from; + private IndexSearcher to; + private long totalHits; + + public JoinSearchTask(PerfRunData runData) { + super(runData); + random = new Random(runData.getConfig().get("join.seed", 42)); + scoreMode = ScoreMode.valueOf(runData.getConfig().get("join.scoreMode", "None")); + } + + @Override + public void setup() throws Exception { + super.setup(); + if (fromManager == null) { + JoinIndices indices = JoinIndices.get(getRunData()); + String layout = algorithm.equals("globalOrd") ? "mixed" : algorithm; + boolean split = algorithm.equals("term") || algorithm.equals("numeric"); Review Comment: `setup()` will throw a `NullPointerException` if `setParams` was not called (i.e., `algorithm` is still null). Since this is a benchmark task that can be invoked from alg files, it’s better to fail fast with a clear `IllegalStateException`/`IllegalArgumentException` explaining the required params (term|numeric|globalOrd|block). ########## lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/JoinIndices.java: ########## @@ -0,0 +1,176 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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.apache.lucene.benchmark.byTask.tasks; + +import java.io.Closeable; +import java.io.IOException; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; +import org.apache.lucene.benchmark.byTask.PerfRunData; +import org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker; +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.IndexWriter; +import org.apache.lucene.index.IndexWriterConfig; +import org.apache.lucene.index.IndexWriterConfig.OpenMode; +import org.apache.lucene.index.MultiDocValues; +import org.apache.lucene.index.OrdinalMap; +import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.SearcherFactory; +import org.apache.lucene.search.SearcherManager; +import org.apache.lucene.store.Directory; +import org.apache.lucene.store.FSDirectory; +import org.apache.lucene.util.IOUtils; +import org.apache.lucene.util.NamedThreadFactory; + +/** + * Writers and NRT searchers over the join indices at <b>join.dir</b>/{layout}/index (Default: + * work/join), shared by join tasks and closed with {@link PerfRunData}. Updates are never + * committed, so the indices stay intact for the next run. + * + * <p><b>join.searchThreads</b> - size of the executor shared by all searchers, i.e. segment + * parallel search on both join sides. Fixed per run, since searchers are only recreated on refresh. + * Default: 0, search segments sequentially. + */ +final class JoinIndices implements Closeable { + + /** + * Searcher that carries the global ordinals of {@link JoinDocMaker#FK} for the mixed index. They + * are built by the first query on each new searcher, so a cold search after refresh pays for + * them. + */ + static final class JoinSearcher extends IndexSearcher { + private final boolean ordinals; + private OrdinalMap ordinalMap; + private boolean built; + + JoinSearcher(IndexReader reader, Executor executor, boolean ordinals) { + super(reader, executor); + this.ordinals = ordinals; + } + + synchronized OrdinalMap ordinalMap() throws IOException { + if (ordinals && !built) { + if (MultiDocValues.getSortedValues(getIndexReader(), JoinDocMaker.FK) + instanceof MultiDocValues.MultiSortedDocValues multi) { + ordinalMap = multi.mapping; // a single segment needs no ordinal map + } + built = true; + } + return ordinalMap; + } + } + + record Index(Directory dir, IndexWriter writer, SearcherManager manager) {} + + private final Path root; + private final ExecutorService executor; + private final Map<String, Index> indices = new HashMap<>(); + + private JoinIndices(Path root, int searchThreads) { + this.root = root; + ThreadFactory named = new NamedThreadFactory("join-search"); + // daemon, since Benchmark never closes PerfRunData, and the pool must not keep the JVM alive + executor = + searchThreads > 0 + ? Executors.newFixedThreadPool( + searchThreads, + r -> { + Thread thread = named.newThread(r); + thread.setDaemon(true); + return thread; + }) + : null; + } + + static JoinIndices get(PerfRunData runData) { + synchronized (runData) { + JoinIndices indices = (JoinIndices) runData.getPerfObject(JoinIndices.class.getName()); + if (indices == null) { + indices = + new JoinIndices( + Path.of(runData.getConfig().get("join.dir", "work/join")), + runData.getConfig().get("join.searchThreads", 0)); + runData.setPerfObject(JoinIndices.class.getName(), indices); + } + return indices; + } + } + + synchronized Index index(String layout) throws IOException { + Index index = indices.get(layout); + if (index == null) { + Directory dir = FSDirectory.open(root.resolve(layout).resolve("index")); + IndexWriter writer = + new IndexWriter( + dir, new IndexWriterConfig().setOpenMode(OpenMode.APPEND).setCommitOnClose(false)); + boolean ordinals = layout.equals("mixed"); + SearcherManager manager = + new SearcherManager( + writer, + new SearcherFactory() { + @Override + public IndexSearcher newSearcher(IndexReader reader, IndexReader previous) { + return new JoinSearcher(reader, executor, ordinals); + } + }); + index = new Index(dir, writer, manager); + indices.put(layout, index); + } + return index; + } + + @Override + public synchronized void close() throws IOException { + IOException firstException = null; + for (Index index : indices.values()) { + try { + index.manager().close(); + } catch (IOException e) { + firstException = e; + } Review Comment: Exception aggregation is inconsistent: an exception from `index.manager().close()` overwrites `firstException`, potentially losing earlier failures from previous indices. Consider using the same pattern as later blocks (set if null; otherwise add as suppressed) so all close failures are preserved. ########## lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/JoinUpdateTask.java: ########## @@ -0,0 +1,162 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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.apache.lucene.benchmark.byTask.tasks; + +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.ID; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.PID; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.productId; +import static org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.skuId; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import org.apache.lucene.benchmark.byTask.PerfRunData; +import org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker; +import org.apache.lucene.benchmark.byTask.feeds.JoinDocMaker.Dataset; +import org.apache.lucene.index.IndexWriter; +import org.apache.lucene.index.Term; + +/** + * Overrides a batch of random existing products and/or skus with new versions of their values (see + * {@link JoinDocMaker}), then refreshes the {@link JoinIndices} searchers, so it measures update + * plus NRT reopen. Data size and seed come from the {@link Dataset} recorded in the index at + * indexing time. + * + * <p>The parameter is the layout group: <b>split</b> (products and skus indices), <b>mixed</b> or + * <b>block</b>. The block layout rewrites the whole product block on any update, i.e. suffers + * update amplification. All groups draw the same update sequence from <b>join.seed</b>, so after + * the same number of updates all join algorithms agree. + * + * <p>Other config properties: <b>join.update.side</b> - products | skus | both. Default: both; + * <b>join.update.batch</b> - updates per task run. Default: 100. + */ +public class JoinUpdateTask extends PerfTask { + + /** Update sequence and the latest version of each updated doc, per layout group. */ + private static final class Versions { + final Random random; + final Map<Long, Long> products = new HashMap<>(); + final Map<Long, Long> skus = new HashMap<>(); + long version; + + Versions(long seed) { + random = new Random(seed); + } + } + + private final String side; + private final int batch; + private String group; + private JoinIndices.Index productIndex; + private JoinIndices.Index skuIndex; + private Versions versions; + private Dataset docs; + + public JoinUpdateTask(PerfRunData runData) { + super(runData); + side = runData.getConfig().get("join.update.side", "both"); + batch = runData.getConfig().get("join.update.batch", 100); + if (!List.of("products", "skus", "both").contains(side)) { + throw new IllegalArgumentException("join.update.side: " + side); + } + } + + @Override + public void setup() throws Exception { + super.setup(); + if (versions == null) { + PerfRunData runData = getRunData(); + JoinIndices indices = JoinIndices.get(runData); + productIndex = indices.index(group.equals("split") ? "products" : group); + skuIndex = indices.index(group.equals("split") ? "skus" : group); Review Comment: `setup()` will throw a `NullPointerException` if `setParams` was not called (i.e., `group` is null). Please add an explicit validation with a clear error message indicating that params must be one of (split|mixed|block). -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
