From 5a6290359c0e12f2372c8470de636796928921cc Mon Sep 17 00:00:00 2001
From: broustant
+ * Protected access to be called by extending class.
+ *
+ * This method can be overridden.
+ * true if the exception has been thrown because the resource could not
+ * be accessed (missing or cannot be read) or the config file is empty; false if the resource has
+ * been found and accessed but the error occurred while loading the resource
+ * (invalid format, incomplete or corrupted).
+ * @return The {@link ElevationProvider} to use if the exception is absorbed.
+ * @throws E If the exception is not absorbed.
*/
- void setTopQueryResults(IndexReader reader, String query, String[] ids, String[] ex) throws IOException {
- if (ids == null) {
- ids = new String[0];
+ private
Can be overridden by extending class.
+ */ + @SuppressWarnings("WeakerAccess") + protected boolean getDefaultKeepElevationPriority() { + return DEFAULT_KEEP_ELEVATION_PRIORITY; + } - public ElevationComparatorSource(final QueryElevationComponent.ElevationObj elevations) { - this.elevations = elevations; - int size = elevations.ids.size(); - ordSet = new SentinelIntSet(size, -1); - termValues = new BytesRef[ordSet.keys.length]; + /** + * Gets the default subset match policy. + *Can be overridden by extending class.
+ */ + @SuppressWarnings("WeakerAccess") + protected boolean getDefaultSubsetMatch() { + return DEFAULT_SUBSET_MATCH; } - @Override - public FieldComparatorCan be overridden by extending class. This method provides a mean to set a custom exception handler if a + * specific error processing is needed.
+ */ + @SuppressWarnings("WeakerAccess") + protected InitializationExceptionHandler getInitializationExceptionHandler() { + return InitializationExceptionHandler.NO_OP; + } + + /** + * Gets the {@link LoadingExceptionHandler} that handles exception thrown during the loading of the elevation configuration. + *Can be overridden by extending class. This method provides a mean to set a custom exception handler if a + * specific error processing is needed.
+ */ + @SuppressWarnings("WeakerAccess") + protected LoadingExceptionHandler getConfigLoadingExceptionHandler() { + return LoadingExceptionHandler.NO_OP; + } + + /** + * Creates the {@link ElevationProvider} to set during configuration loading. The same instance will be used later + * when elevating results for queries. + *+ * Extending classes can override this method to create {@link ElevationProvider} with different behavior. + *
+ * + * @param queryAnalyzer to analyze and tokenize the query. + * @return The created {@link ElevationProvider}. + */ + @SuppressWarnings("WeakerAccess") + protected ElevationProvider createElevationProvider(Analyzer queryAnalyzer) { + return new MapElevationProvider(queryAnalyzer); + } + + //--------------------------------------------------------------------------------- + // Query analysis and tokenization + //--------------------------------------------------------------------------------- + + @VisibleForTesting + String analyzeQuery(String queryString) throws IOException { + return analyzeQuery(queryString, queryAnalyzer); + } + + /** + * Analyzes the provided query string and returns a concatenation of the analyzed tokens. + */ + private static String analyzeQuery(String queryString, Analyzer queryAnalyzer) throws IOException { + if (queryAnalyzer == null) { + return queryString; + } + Collectiontrue for query subset match; false for query exact match.
+ * @param elevatedIds The readable ids of the documents to set as top results for the provided query.
+ * @param excludedIds The readable ids of the document to exclude from results for the provided query.
+ * @throws java.io.IOException If there is a low-level I/O error.
+ */
+ @VisibleForTesting
+ void setTopQueryResults(IndexReader reader, String queryString, boolean subsetMatch, String[] elevatedIds,
+ String[] excludedIds) throws IOException {
+ clearElevationProviderCache();
+ if (elevatedIds == null) {
+ elevatedIds = new String[0];
+ }
+ if (excludedIds == null) {
+ excludedIds = new String[0];
+ }
+ ElevatingQuery elevatingQuery = new ElevatingQuery(queryString, subsetMatch);
+ Elevation elevation = createElevation(Arrays.asList(elevatedIds), Arrays.asList(excludedIds));
+ ElevationProvider elevationProvider;
+ synchronized (elevationProviderCache) {
+ elevationProvider = elevationProviderCache.computeIfAbsent(reader, k -> createElevationProvider(queryAnalyzer));
+ }
+ elevationProvider.setElevationForQuery(elevatingQuery, elevation);
+ }
+
+ @VisibleForTesting
+ void clearElevationProviderCache() {
+ synchronized (elevationProviderCache) {
+ elevationProviderCache.clear();
+ }
+ }
+
+ //---------------------------------------------------------------------------------
+ // Exception classes
+ //---------------------------------------------------------------------------------
+
+ private static class InitializationException extends Exception {
+ final InitializationExceptionHandler.ExceptionCause exceptionCause;
+
+ InitializationException(String message, InitializationExceptionHandler.ExceptionCause exceptionCause) {
+ super(message);
+ this.exceptionCause = exceptionCause;
+ }
+ }
+
+ /**
+ * Handles resource loading exception.
+ */
+ protected interface InitializationExceptionHandler {
+ /**
+ * NoOp {@link LoadingExceptionHandler} that does not capture any exception and simply returns false.
+ */
+ InitializationExceptionHandler NO_OP = new InitializationExceptionHandler() {
@Override
- public int compare(int slot1, int slot2) {
- return values[slot1] - values[slot2]; // values will be small enough that there is no overflow concern
+ public boolean handleInitializationException(Exception e, ExceptionCause exceptionCause) {
+ return exceptionCause == ExceptionCause.NO_CONFIG_FILE_DEFINED;
}
+ };
+
+ enum ExceptionCause {
+ /**
+ * The component parameter {@link #FIELD_TYPE} defines an unknown field type.
+ */
+ UNKNOWN_FIELD_TYPE,
+ /**
+ * This component requires the schema to have a uniqueKeyField, which it does not have.
+ */
+ MISSING_UNIQUE_KEY_FIELD,
+ /**
+ * Missing component parameter {@link #CONFIG_FILE} - it has to define the path to the elevation configuration file (e.g. elevate.xml).
+ */
+ NO_CONFIG_FILE_DEFINED,
+ /**
+ * The elevation configuration file (e.g. elevate.xml) cannot be found, or is defined in both conf/ and data/ directories.
+ */
+ MISSING_CONFIG_FILE,
+ /**
+ * The elevation configuration file (e.g. elevate.xml) is empty.
+ */
+ EMPTY_CONFIG_FILE,
+ /**
+ * Unclassified exception cause.
+ */
+ OTHER,
+ }
+
+ /**
+ * Potentially handles and captures an exception that occurred while initializing the component.
+ * If the exception is captured, the component fails to initialize silently and is muted.
+ *
+ * @param e The exception caught.
+ * @param exceptionCause The exception cause.
+ * @param true if the exception is handled and captured by this handler (and thus will not be
+ * thrown anymore); false if the exception is not captured, in this case it will be probably
+ * thrown again by the calling code.
+ * @throws E If this handler throws the exception itself (it may add some cause or message).
+ */
+ false.
+ */
+ LoadingExceptionHandler NO_OP = new LoadingExceptionHandler() {
@Override
- public void setBottom(int slot) {
- bottomVal = values[slot];
+ public boolean handleLoadingException(Exception e, boolean resourceAccessIssue) {
+ return false;
}
@Override
- public void setTopValue(Integer value) {
- topVal = value.intValue();
+ public int getLoadingMaxAttempts() {
+ return 0;
}
+ };
- private int docVal(int doc) {
- if (ordSet.size() > 0) {
- int slot = ordSet.find(doc);
- if (slot >= 0) {
- BytesRef id = termValues[slot];
- Integer prio = elevations.priority.get(id);
- return prio == null ? 0 : prio.intValue();
- }
- }
- return 0;
+ /**
+ * Potentially handles and captures an exception that occurred while loading a resource.
+ *
+ * @param e The exception caught.
+ * @param resourceAccessIssue true if the exception has been thrown because the resource could not
+ * be accessed (missing or cannot be read); false if the resource has
+ * been found and accessed but the error occurred while loading the resource
+ * (invalid format, incomplete or corrupted).
+ * @param true if the exception is handled and captured by this handler (and thus will not be
+ * thrown anymore); false if the exception is not captured, in this case it will be probably
+ * thrown again by the calling code.
+ * @throws E If this handler throws the exception itself (it may add some cause or message).
+ */
+ null.
+ * @param excludedIds The ids of the excluded documents that should not appear in search results; can be null.
+ */
+ private Elevation createElevation(Collectionnull if none.
+ */
+ Elevation getElevationForQuery(String queryString) throws IOException;
+
+ /**
+ * Sets the elevation for the provided query.
+ * + * By contract and by design, only one elevation may be associated + * to a given query (this can be safely verified by an assertion). + *
+ *+ * It is not allowed to call this method once this {@link ElevationProvider} becomes {@link #makeImmutable() immutable}. + * Otherwise a {@link RuntimeException} may be thrown. + *
+ * + * @param elevatingQuery The query triggering elevation. + * @param elevation The elevation. + */ + void setElevationForQuery(ElevatingQuery elevatingQuery, Elevation elevation) throws IOException; + + /** + * Gets the number of query elevations in this {@link ElevationProvider}. + */ + int size(); + + /** + * Makes this elevation provider immutable. + *Calling {@link #setElevationForQuery} afterwards will throw an exception.
+ *Making this elevation provider immutable may reduce its memory usage and make it more efficient.
+ * + * @return This elevation provider. + */ + ElevationProvider makeImmutable(); + } + + /** + * {@link ElevationProvider} that returns no elevation. + */ + @SuppressWarnings("WeakerAccess") + protected static final ElevationProvider NO_OP_ELEVATION_PROVIDER = new ElevationProvider() { + @Override + public Elevation getElevationForQuery(String queryString) { + return null; + } + + @Override + public void setElevationForQuery(ElevatingQuery elevatingQuery, Elevation elevation) { + // Do nothing. + } + + @Override + public int size() { + return 0; + } + + @Override + public ElevationProvider makeImmutable() { + return this; + } + }; + + /** + * Simple query exact match {@link ElevationProvider}. + *+ * It does not support subset matching (see {@link #parseMatchPolicy(String)}). + *
+ */ + protected static class MapElevationProvider implements ElevationProvider { + + private final Analyzer queryAnalyzer; + private Mapnull.
+ */
+ private Setnull.
+ */
+ private Setnull.
+ * @param excludedIds The ids of the excluded documents that should not appear in search results; can be null.
+ * @param indexedValueProvider Provides indexed values.
+ * @param queryFieldName The field name to use to create query terms.
+ * @param keepElevationPriority Whether to keep the elevation priority order.
+ */
+ private Elevation(Collectiontrue.
+ */
+ String KEEP_ELEVATION_PRIORITY = "keepElevationPriority";
}
From e9f53315ef0dc230280e93f868055183aa09abb6 Mon Sep 17 00:00:00 2001
From: broustant - * This method can be overridden. - *
* * @throws java.io.IOException If an I/O error occurs while analyzing the triggering queries. * @throws RuntimeException If the config does not provide an XML content of the expected format @@ -403,11 +400,7 @@ protected ElevationProvider loadElevationProvider(Config config) throws IOExcept previousElevationBuilder.merge(elevationBuilder); } } - ElevationProvider elevationProvider = createElevationProvider(queryAnalyzer); - for (Map.EntryCan be overridden by extending this class.
*/ @SuppressWarnings("WeakerAccess") protected boolean getDefaultForceElevation() { @@ -724,7 +712,6 @@ protected boolean getDefaultForceElevation() { /** * Gets the default value for {@link #DEFAULT_KEEP_ELEVATION_PRIORITY} parameter. - *Can be overridden by extending class.
*/ @SuppressWarnings("WeakerAccess") protected boolean getDefaultKeepElevationPriority() { @@ -733,7 +720,6 @@ protected boolean getDefaultKeepElevationPriority() { /** * Gets the default subset match policy. - *Can be overridden by extending class.
*/ @SuppressWarnings("WeakerAccess") protected boolean getDefaultSubsetMatch() { @@ -743,8 +729,6 @@ protected boolean getDefaultSubsetMatch() { /** * Gets the {@link InitializationExceptionHandler} that handles exception thrown during the initialization of the * elevation configuration. - *Can be overridden by extending class. This method provides a mean to set a custom exception handler if a - * specific error processing is needed.
*/ @SuppressWarnings("WeakerAccess") protected InitializationExceptionHandler getInitializationExceptionHandler() { @@ -753,8 +737,6 @@ protected InitializationExceptionHandler getInitializationExceptionHandler() { /** * Gets the {@link LoadingExceptionHandler} that handles exception thrown during the loading of the elevation configuration. - *Can be overridden by extending class. This method provides a mean to set a custom exception handler if a - * specific error processing is needed.
*/ @SuppressWarnings("WeakerAccess") protected LoadingExceptionHandler getConfigLoadingExceptionHandler() { @@ -764,16 +746,14 @@ protected LoadingExceptionHandler getConfigLoadingExceptionHandler() { /** * Creates the {@link ElevationProvider} to set during configuration loading. The same instance will be used later * when elevating results for queries. - *- * Extending classes can override this method to create {@link ElevationProvider} with different behavior. - *
* * @param queryAnalyzer to analyze and tokenize the query. + * @param elevationBuilderMap map of all {@link ElevatingQuery} and their corresponding {@link ElevationBuilder}. * @return The created {@link ElevationProvider}. */ @SuppressWarnings("WeakerAccess") - protected ElevationProvider createElevationProvider(Analyzer queryAnalyzer) { - return new MapElevationProvider(queryAnalyzer); + protected ElevationProvider createElevationProvider(Analyzer queryAnalyzer, Map* By contract and by design, only one elevation may be associated * to a given query (this can be safely verified by an assertion). - *
- *- * It is not allowed to call this method once this {@link ElevationProvider} becomes {@link #makeImmutable() immutable}. - * Otherwise a {@link RuntimeException} may be thrown. - *
* - * @param elevatingQuery The query triggering elevation. - * @param elevation The elevation. + * @param queryString The query string (not {@link #analyzeQuery(String, Analyzer) analyzed} yet, + * this {@link ElevationProvider} is in charge of analyzing it). + * @return The elevation associated with the query; ornull if none.
*/
- void setElevationForQuery(ElevatingQuery elevatingQuery, Elevation elevation) throws IOException;
+ Elevation getElevationForQuery(String queryString);
/**
* Gets the number of query elevations in this {@link ElevationProvider}.
*/
+ @VisibleForTesting
int size();
-
- /**
- * Makes this elevation provider immutable.
- * Calling {@link #setElevationForQuery} afterwards will throw an exception.
- *Making this elevation provider immutable may reduce its memory usage and make it more efficient.
- * - * @return This elevation provider. - */ - ElevationProvider makeImmutable(); } /** @@ -1036,63 +1001,56 @@ public Elevation getElevationForQuery(String queryString) { return null; } - @Override - public void setElevationForQuery(ElevatingQuery elevatingQuery, Elevation elevation) { - // Do nothing. - } - @Override public int size() { return 0; } - - @Override - public ElevationProvider makeImmutable() { - return this; - } }; /** * Simple query exact match {@link ElevationProvider}. ** It does not support subset matching (see {@link #parseMatchPolicy(String)}). - *
+ *
+ * Immutable.
*/
protected static class MapElevationProvider implements ElevationProvider {
private final Analyzer queryAnalyzer;
- private Map
- * Protected access to be called by extending class.
- *
+ * Protected access to be called by extending class.
+ *
+ * This method can be overridden.
+ * null.
* @param excludedIds The ids of the excluded documents that should not appear in search results; can be null.
- * @param indexedValueProvider Provides indexed values.
+ * @param indexedValueProvider Provides the indexed value corresponding to a readable value..
* @param queryFieldName The field name to use to create query terms.
* @param keepElevationPriority Whether to keep the elevation priority order.
*/
private Elevation(Collectiontrue if the exception has been thrown
+ * because the resource could not be accessed (missing or cannot be read)
+ * or the config file is empty; false if the resource has
+ * been found and accessed but the error occurred while loading the resource
+ * (invalid format, incomplete or corrupted).
+ * @return The {@link ElevationProvider} to use if the exception is absorbed. If {@code null}
+ * is returned, the {@link #NO_OP_ELEVATION_PROVIDER} is used but not cached in
+ * the {@link ElevationProvider} cache.
+ * @throws E If the exception is not absorbed.
+ */
+ protected true if the exception has been thrown because the resource could not
- * be accessed (missing or cannot be read) or the config file is empty; false if the resource has
- * been found and accessed but the error occurred while loading the resource
- * (invalid format, incomplete or corrupted).
- * @return The {@link ElevationProvider} to use if the exception is absorbed.
- * @throws E If the exception is not absorbed.
- */
- private false.
- */
- InitializationExceptionHandler NO_OP = new InitializationExceptionHandler() {
- @Override
- public boolean handleInitializationException(Exception e, ExceptionCause exceptionCause) {
- return exceptionCause == ExceptionCause.NO_CONFIG_FILE_DEFINED;
+ protected enum InitializationExceptionCause {
+ /**
+ * The component parameter {@link #FIELD_TYPE} defines an unknown field type.
+ */
+ UNKNOWN_FIELD_TYPE,
+ /**
+ * This component requires the schema to have a uniqueKeyField, which it does not have.
+ */
+ MISSING_UNIQUE_KEY_FIELD,
+ /**
+ * Missing component parameter {@link #CONFIG_FILE} - it has to define the path to the elevation configuration file (e.g. elevate.xml).
+ */
+ NO_CONFIG_FILE_DEFINED,
+ /**
+ * The elevation configuration file (e.g. elevate.xml) cannot be found, or is defined in both conf/ and data/ directories.
+ */
+ MISSING_CONFIG_FILE,
+ /**
+ * The elevation configuration file (e.g. elevate.xml) is empty.
+ */
+ EMPTY_CONFIG_FILE,
+ /**
+ * Unclassified exception cause.
+ */
+ OTHER,
}
- };
-
- enum ExceptionCause {
- /**
- * The component parameter {@link #FIELD_TYPE} defines an unknown field type.
- */
- UNKNOWN_FIELD_TYPE,
- /**
- * This component requires the schema to have a uniqueKeyField, which it does not have.
- */
- MISSING_UNIQUE_KEY_FIELD,
- /**
- * Missing component parameter {@link #CONFIG_FILE} - it has to define the path to the elevation configuration file (e.g. elevate.xml).
- */
- NO_CONFIG_FILE_DEFINED,
- /**
- * The elevation configuration file (e.g. elevate.xml) cannot be found, or is defined in both conf/ and data/ directories.
- */
- MISSING_CONFIG_FILE,
- /**
- * The elevation configuration file (e.g. elevate.xml) is empty.
- */
- EMPTY_CONFIG_FILE,
- /**
- * Unclassified exception cause.
- */
- OTHER,
- }
-
- /**
- * Potentially handles and captures an exception that occurred while initializing the component.
- * If the exception is captured, the component fails to initialize silently and is muted.
- *
- * @param e The exception caught.
- * @param exceptionCause The exception cause.
- * @param true if the exception is handled and captured by this handler (and thus will not be
- * thrown anymore); false if the exception is not captured, in this case it will be probably
- * thrown again by the calling code.
- * @throws E If this handler throws the exception itself (it may add some cause or message).
- */
- false.
- */
- LoadingExceptionHandler NO_OP = new LoadingExceptionHandler() {
- @Override
- public boolean handleLoadingException(Exception e, boolean resourceAccessIssue) {
- return false;
- }
-
- @Override
- public int getLoadingMaxAttempts() {
- return 0;
- }
- };
-
- /**
- * Potentially handles and captures an exception that occurred while loading a resource.
- *
- * @param e The exception caught.
- * @param resourceAccessIssue true if the exception has been thrown because the resource could not
- * be accessed (missing or cannot be read); false if the resource has
- * been found and accessed but the error occurred while loading the resource
- * (invalid format, incomplete or corrupted).
- * @param true if the exception is handled and captured by this handler (and thus will not be
- * thrown anymore); false if the exception is not captured, in this case it will be probably
- * thrown again by the calling code.
- * @throws E If this handler throws the exception itself (it may add some cause or message).
- */
- true if the exception has been thrown
* because the resource could not be accessed (missing or cannot be read)
* or the config file is empty; false if the resource has
* been found and accessed but the error occurred while loading the resource
* (invalid format, incomplete or corrupted).
* @return The {@link ElevationProvider} to use if the exception is absorbed. If {@code null}
- * is returned, the {@link #NO_OP_ELEVATION_PROVIDER} is used but not cached in
- * the {@link ElevationProvider} cache.
+ * is returned, the {@link #NO_OP_ELEVATION_PROVIDER} is used but not cached in
+ * the {@link ElevationProvider} cache.
* @throws E If the exception is not absorbed.
*/
protected null.
- * @param excludedIds The ids of the excluded documents that should not appear in search results; can be null.
- */
- private Elevation createElevation(Collectionnull.
*/
- private Setnull.
+ * In configured order.
* @param excludedIds The ids of the excluded documents that should not appear in search results; can be null.
- * @param indexedValueProvider Provides the indexed value corresponding to a readable value..
* @param queryFieldName The field name to use to create query terms.
- * @param keepElevationPriority Whether to keep the elevation priority order.
*/
- private Elevation(Collectiontrue.
+ * When multiple docs are elevated, should their relative order be the order in the configuration file or should
+ * they be subject to whatever the sort criteria is? True by default.
*/
- String KEEP_ELEVATION_PRIORITY = "keepElevationPriority";
+ String USE_CONFIGURED_ELEVATED_ORDER = "useConfiguredElevatedOrder";
}
From aaf69cc361153786c6f117a3483c06bb02261a74 Mon Sep 17 00:00:00 2001
From: broustant true if the exception has been thrown because the resource could not
+ * be accessed (missing or cannot be read) or the config file is empty; false if the resource has
+ * been found and accessed but the error occurred while loading the resource
+ * (invalid format, incomplete or corrupted).
+ * @return The {@link ElevationProvider} to use if the exception is absorbed.
+ * @throws E If the exception is not absorbed.
*/
- void setTopQueryResults(IndexReader reader, String query, String[] ids, String[] ex) throws IOException {
- if (ids == null) {
- ids = new String[0];
+ private
Can be overridden by extending class.
+ */ + @SuppressWarnings("WeakerAccess") + protected boolean getDefaultKeepElevationPriority() { + return DEFAULT_KEEP_ELEVATION_PRIORITY; + } - public ElevationComparatorSource(final QueryElevationComponent.ElevationObj elevations) { - this.elevations = elevations; - int size = elevations.ids.size(); - ordSet = new SentinelIntSet(size, -1); - termValues = new BytesRef[ordSet.keys.length]; + /** + * Gets the default subset match policy. + *Can be overridden by extending class.
+ */ + @SuppressWarnings("WeakerAccess") + protected boolean getDefaultSubsetMatch() { + return DEFAULT_SUBSET_MATCH; } - @Override - public FieldComparatorCan be overridden by extending class. This method provides a mean to set a custom exception handler if a + * specific error processing is needed.
+ */ + @SuppressWarnings("WeakerAccess") + protected InitializationExceptionHandler getInitializationExceptionHandler() { + return InitializationExceptionHandler.NO_OP; + } + + /** + * Gets the {@link LoadingExceptionHandler} that handles exception thrown during the loading of the elevation configuration. + *Can be overridden by extending class. This method provides a mean to set a custom exception handler if a + * specific error processing is needed.
+ */ + @SuppressWarnings("WeakerAccess") + protected LoadingExceptionHandler getConfigLoadingExceptionHandler() { + return LoadingExceptionHandler.NO_OP; + } + + /** + * Creates the {@link ElevationProvider} to set during configuration loading. The same instance will be used later + * when elevating results for queries. + *+ * Extending classes can override this method to create {@link ElevationProvider} with different behavior. + *
+ * + * @param queryAnalyzer to analyze and tokenize the query. + * @return The created {@link ElevationProvider}. + */ + @SuppressWarnings("WeakerAccess") + protected ElevationProvider createElevationProvider(Analyzer queryAnalyzer) { + return new MapElevationProvider(queryAnalyzer); + } + + //--------------------------------------------------------------------------------- + // Query analysis and tokenization + //--------------------------------------------------------------------------------- + + @VisibleForTesting + String analyzeQuery(String queryString) throws IOException { + return analyzeQuery(queryString, queryAnalyzer); + } + + /** + * Analyzes the provided query string and returns a concatenation of the analyzed tokens. + */ + private static String analyzeQuery(String queryString, Analyzer queryAnalyzer) throws IOException { + if (queryAnalyzer == null) { + return queryString; + } + Collectiontrue for query subset match; false for query exact match.
+ * @param elevatedIds The readable ids of the documents to set as top results for the provided query.
+ * @param excludedIds The readable ids of the document to exclude from results for the provided query.
+ * @throws java.io.IOException If there is a low-level I/O error.
+ */
+ @VisibleForTesting
+ void setTopQueryResults(IndexReader reader, String queryString, boolean subsetMatch, String[] elevatedIds,
+ String[] excludedIds) throws IOException {
+ clearElevationProviderCache();
+ if (elevatedIds == null) {
+ elevatedIds = new String[0];
+ }
+ if (excludedIds == null) {
+ excludedIds = new String[0];
+ }
+ ElevatingQuery elevatingQuery = new ElevatingQuery(queryString, subsetMatch);
+ Elevation elevation = createElevation(Arrays.asList(elevatedIds), Arrays.asList(excludedIds));
+ ElevationProvider elevationProvider;
+ synchronized (elevationProviderCache) {
+ elevationProvider = elevationProviderCache.computeIfAbsent(reader, k -> createElevationProvider(queryAnalyzer));
+ }
+ elevationProvider.setElevationForQuery(elevatingQuery, elevation);
+ }
+
+ @VisibleForTesting
+ void clearElevationProviderCache() {
+ synchronized (elevationProviderCache) {
+ elevationProviderCache.clear();
+ }
+ }
+
+ //---------------------------------------------------------------------------------
+ // Exception classes
+ //---------------------------------------------------------------------------------
+
+ private static class InitializationException extends Exception {
+ final InitializationExceptionHandler.ExceptionCause exceptionCause;
+
+ InitializationException(String message, InitializationExceptionHandler.ExceptionCause exceptionCause) {
+ super(message);
+ this.exceptionCause = exceptionCause;
+ }
+ }
+
+ /**
+ * Handles resource loading exception.
+ */
+ protected interface InitializationExceptionHandler {
+ /**
+ * NoOp {@link LoadingExceptionHandler} that does not capture any exception and simply returns false.
+ */
+ InitializationExceptionHandler NO_OP = new InitializationExceptionHandler() {
@Override
- public int compare(int slot1, int slot2) {
- return values[slot1] - values[slot2]; // values will be small enough that there is no overflow concern
+ public boolean handleInitializationException(Exception e, ExceptionCause exceptionCause) {
+ return exceptionCause == ExceptionCause.NO_CONFIG_FILE_DEFINED;
}
+ };
+
+ enum ExceptionCause {
+ /**
+ * The component parameter {@link #FIELD_TYPE} defines an unknown field type.
+ */
+ UNKNOWN_FIELD_TYPE,
+ /**
+ * This component requires the schema to have a uniqueKeyField, which it does not have.
+ */
+ MISSING_UNIQUE_KEY_FIELD,
+ /**
+ * Missing component parameter {@link #CONFIG_FILE} - it has to define the path to the elevation configuration file (e.g. elevate.xml).
+ */
+ NO_CONFIG_FILE_DEFINED,
+ /**
+ * The elevation configuration file (e.g. elevate.xml) cannot be found, or is defined in both conf/ and data/ directories.
+ */
+ MISSING_CONFIG_FILE,
+ /**
+ * The elevation configuration file (e.g. elevate.xml) is empty.
+ */
+ EMPTY_CONFIG_FILE,
+ /**
+ * Unclassified exception cause.
+ */
+ OTHER,
+ }
+
+ /**
+ * Potentially handles and captures an exception that occurred while initializing the component.
+ * If the exception is captured, the component fails to initialize silently and is muted.
+ *
+ * @param e The exception caught.
+ * @param exceptionCause The exception cause.
+ * @param true if the exception is handled and captured by this handler (and thus will not be
+ * thrown anymore); false if the exception is not captured, in this case it will be probably
+ * thrown again by the calling code.
+ * @throws E If this handler throws the exception itself (it may add some cause or message).
+ */
+ false.
+ */
+ LoadingExceptionHandler NO_OP = new LoadingExceptionHandler() {
@Override
- public void setBottom(int slot) {
- bottomVal = values[slot];
+ public boolean handleLoadingException(Exception e, boolean resourceAccessIssue) {
+ return false;
}
@Override
- public void setTopValue(Integer value) {
- topVal = value.intValue();
+ public int getLoadingMaxAttempts() {
+ return 0;
}
+ };
- private int docVal(int doc) {
- if (ordSet.size() > 0) {
- int slot = ordSet.find(doc);
- if (slot >= 0) {
- BytesRef id = termValues[slot];
- Integer prio = elevations.priority.get(id);
- return prio == null ? 0 : prio.intValue();
- }
- }
- return 0;
+ /**
+ * Potentially handles and captures an exception that occurred while loading a resource.
+ *
+ * @param e The exception caught.
+ * @param resourceAccessIssue true if the exception has been thrown because the resource could not
+ * be accessed (missing or cannot be read); false if the resource has
+ * been found and accessed but the error occurred while loading the resource
+ * (invalid format, incomplete or corrupted).
+ * @param true if the exception is handled and captured by this handler (and thus will not be
+ * thrown anymore); false if the exception is not captured, in this case it will be probably
+ * thrown again by the calling code.
+ * @throws E If this handler throws the exception itself (it may add some cause or message).
+ */
+ null.
+ * @param excludedIds The ids of the excluded documents that should not appear in search results; can be null.
+ */
+ private Elevation createElevation(Collectionnull if none.
+ */
+ Elevation getElevationForQuery(String queryString) throws IOException;
+
+ /**
+ * Sets the elevation for the provided query.
+ * + * By contract and by design, only one elevation may be associated + * to a given query (this can be safely verified by an assertion). + *
+ *+ * It is not allowed to call this method once this {@link ElevationProvider} becomes {@link #makeImmutable() immutable}. + * Otherwise a {@link RuntimeException} may be thrown. + *
+ * + * @param elevatingQuery The query triggering elevation. + * @param elevation The elevation. + */ + void setElevationForQuery(ElevatingQuery elevatingQuery, Elevation elevation) throws IOException; + + /** + * Gets the number of query elevations in this {@link ElevationProvider}. + */ + int size(); + + /** + * Makes this elevation provider immutable. + *Calling {@link #setElevationForQuery} afterwards will throw an exception.
+ *Making this elevation provider immutable may reduce its memory usage and make it more efficient.
+ * + * @return This elevation provider. + */ + ElevationProvider makeImmutable(); + } + + /** + * {@link ElevationProvider} that returns no elevation. + */ + @SuppressWarnings("WeakerAccess") + protected static final ElevationProvider NO_OP_ELEVATION_PROVIDER = new ElevationProvider() { + @Override + public Elevation getElevationForQuery(String queryString) { + return null; + } + + @Override + public void setElevationForQuery(ElevatingQuery elevatingQuery, Elevation elevation) { + // Do nothing. + } + + @Override + public int size() { + return 0; + } + + @Override + public ElevationProvider makeImmutable() { + return this; + } + }; + + /** + * Simple query exact match {@link ElevationProvider}. + *+ * It does not support subset matching (see {@link #parseMatchPolicy(String)}). + *
+ */ + protected static class MapElevationProvider implements ElevationProvider { + + private final Analyzer queryAnalyzer; + private Mapnull.
+ */
+ private Setnull.
+ */
+ private Setnull.
+ * @param excludedIds The ids of the excluded documents that should not appear in search results; can be null.
+ * @param indexedValueProvider Provides indexed values.
+ * @param queryFieldName The field name to use to create query terms.
+ * @param keepElevationPriority Whether to keep the elevation priority order.
+ */
+ private Elevation(Collectiontrue.
+ */
+ String KEEP_ELEVATION_PRIORITY = "keepElevationPriority";
}
From 2699564526bf01887a7119b41167e03663ba9a29 Mon Sep 17 00:00:00 2001
From: broustant - * This method can be overridden. - *
* * @throws java.io.IOException If an I/O error occurs while analyzing the triggering queries. * @throws RuntimeException If the config does not provide an XML content of the expected format @@ -403,11 +400,7 @@ protected ElevationProvider loadElevationProvider(Config config) throws IOExcept previousElevationBuilder.merge(elevationBuilder); } } - ElevationProvider elevationProvider = createElevationProvider(queryAnalyzer); - for (Map.EntryCan be overridden by extending this class.
*/ @SuppressWarnings("WeakerAccess") protected boolean getDefaultForceElevation() { @@ -724,7 +712,6 @@ protected boolean getDefaultForceElevation() { /** * Gets the default value for {@link #DEFAULT_KEEP_ELEVATION_PRIORITY} parameter. - *Can be overridden by extending class.
*/ @SuppressWarnings("WeakerAccess") protected boolean getDefaultKeepElevationPriority() { @@ -733,7 +720,6 @@ protected boolean getDefaultKeepElevationPriority() { /** * Gets the default subset match policy. - *Can be overridden by extending class.
*/ @SuppressWarnings("WeakerAccess") protected boolean getDefaultSubsetMatch() { @@ -743,8 +729,6 @@ protected boolean getDefaultSubsetMatch() { /** * Gets the {@link InitializationExceptionHandler} that handles exception thrown during the initialization of the * elevation configuration. - *Can be overridden by extending class. This method provides a mean to set a custom exception handler if a - * specific error processing is needed.
*/ @SuppressWarnings("WeakerAccess") protected InitializationExceptionHandler getInitializationExceptionHandler() { @@ -753,8 +737,6 @@ protected InitializationExceptionHandler getInitializationExceptionHandler() { /** * Gets the {@link LoadingExceptionHandler} that handles exception thrown during the loading of the elevation configuration. - *Can be overridden by extending class. This method provides a mean to set a custom exception handler if a - * specific error processing is needed.
*/ @SuppressWarnings("WeakerAccess") protected LoadingExceptionHandler getConfigLoadingExceptionHandler() { @@ -764,16 +746,14 @@ protected LoadingExceptionHandler getConfigLoadingExceptionHandler() { /** * Creates the {@link ElevationProvider} to set during configuration loading. The same instance will be used later * when elevating results for queries. - *- * Extending classes can override this method to create {@link ElevationProvider} with different behavior. - *
* * @param queryAnalyzer to analyze and tokenize the query. + * @param elevationBuilderMap map of all {@link ElevatingQuery} and their corresponding {@link ElevationBuilder}. * @return The created {@link ElevationProvider}. */ @SuppressWarnings("WeakerAccess") - protected ElevationProvider createElevationProvider(Analyzer queryAnalyzer) { - return new MapElevationProvider(queryAnalyzer); + protected ElevationProvider createElevationProvider(Analyzer queryAnalyzer, Map* By contract and by design, only one elevation may be associated * to a given query (this can be safely verified by an assertion). - *
- *- * It is not allowed to call this method once this {@link ElevationProvider} becomes {@link #makeImmutable() immutable}. - * Otherwise a {@link RuntimeException} may be thrown. - *
* - * @param elevatingQuery The query triggering elevation. - * @param elevation The elevation. + * @param queryString The query string (not {@link #analyzeQuery(String, Analyzer) analyzed} yet, + * this {@link ElevationProvider} is in charge of analyzing it). + * @return The elevation associated with the query; ornull if none.
*/
- void setElevationForQuery(ElevatingQuery elevatingQuery, Elevation elevation) throws IOException;
+ Elevation getElevationForQuery(String queryString);
/**
* Gets the number of query elevations in this {@link ElevationProvider}.
*/
+ @VisibleForTesting
int size();
-
- /**
- * Makes this elevation provider immutable.
- * Calling {@link #setElevationForQuery} afterwards will throw an exception.
- *Making this elevation provider immutable may reduce its memory usage and make it more efficient.
- * - * @return This elevation provider. - */ - ElevationProvider makeImmutable(); } /** @@ -1036,63 +1001,56 @@ public Elevation getElevationForQuery(String queryString) { return null; } - @Override - public void setElevationForQuery(ElevatingQuery elevatingQuery, Elevation elevation) { - // Do nothing. - } - @Override public int size() { return 0; } - - @Override - public ElevationProvider makeImmutable() { - return this; - } }; /** * Simple query exact match {@link ElevationProvider}. ** It does not support subset matching (see {@link #parseMatchPolicy(String)}). - *
+ *
+ * Immutable.
*/
protected static class MapElevationProvider implements ElevationProvider {
private final Analyzer queryAnalyzer;
- private Map
- * Protected access to be called by extending class.
- * null.
* @param excludedIds The ids of the excluded documents that should not appear in search results; can be null.
- * @param indexedValueProvider Provides indexed values.
+ * @param indexedValueProvider Provides the indexed value corresponding to a readable value..
* @param queryFieldName The field name to use to create query terms.
* @param keepElevationPriority Whether to keep the elevation priority order.
*/
private Elevation(Collectiontrue if the exception has been thrown
+ * because the resource could not be accessed (missing or cannot be read)
+ * or the config file is empty; false if the resource has
+ * been found and accessed but the error occurred while loading the resource
+ * (invalid format, incomplete or corrupted).
+ * @return The {@link ElevationProvider} to use if the exception is absorbed. If {@code null}
+ * is returned, the {@link #NO_OP_ELEVATION_PROVIDER} is used but not cached in
+ * the {@link ElevationProvider} cache.
+ * @throws E If the exception is not absorbed.
+ */
+ protected true if the exception has been thrown because the resource could not
- * be accessed (missing or cannot be read) or the config file is empty; false if the resource has
- * been found and accessed but the error occurred while loading the resource
- * (invalid format, incomplete or corrupted).
- * @return The {@link ElevationProvider} to use if the exception is absorbed.
- * @throws E If the exception is not absorbed.
- */
- private false.
- */
- InitializationExceptionHandler NO_OP = new InitializationExceptionHandler() {
- @Override
- public boolean handleInitializationException(Exception e, ExceptionCause exceptionCause) {
- return exceptionCause == ExceptionCause.NO_CONFIG_FILE_DEFINED;
+ protected enum InitializationExceptionCause {
+ /**
+ * The component parameter {@link #FIELD_TYPE} defines an unknown field type.
+ */
+ UNKNOWN_FIELD_TYPE,
+ /**
+ * This component requires the schema to have a uniqueKeyField, which it does not have.
+ */
+ MISSING_UNIQUE_KEY_FIELD,
+ /**
+ * Missing component parameter {@link #CONFIG_FILE} - it has to define the path to the elevation configuration file (e.g. elevate.xml).
+ */
+ NO_CONFIG_FILE_DEFINED,
+ /**
+ * The elevation configuration file (e.g. elevate.xml) cannot be found, or is defined in both conf/ and data/ directories.
+ */
+ MISSING_CONFIG_FILE,
+ /**
+ * The elevation configuration file (e.g. elevate.xml) is empty.
+ */
+ EMPTY_CONFIG_FILE,
+ /**
+ * Unclassified exception cause.
+ */
+ OTHER,
}
- };
-
- enum ExceptionCause {
- /**
- * The component parameter {@link #FIELD_TYPE} defines an unknown field type.
- */
- UNKNOWN_FIELD_TYPE,
- /**
- * This component requires the schema to have a uniqueKeyField, which it does not have.
- */
- MISSING_UNIQUE_KEY_FIELD,
- /**
- * Missing component parameter {@link #CONFIG_FILE} - it has to define the path to the elevation configuration file (e.g. elevate.xml).
- */
- NO_CONFIG_FILE_DEFINED,
- /**
- * The elevation configuration file (e.g. elevate.xml) cannot be found, or is defined in both conf/ and data/ directories.
- */
- MISSING_CONFIG_FILE,
- /**
- * The elevation configuration file (e.g. elevate.xml) is empty.
- */
- EMPTY_CONFIG_FILE,
- /**
- * Unclassified exception cause.
- */
- OTHER,
- }
-
- /**
- * Potentially handles and captures an exception that occurred while initializing the component.
- * If the exception is captured, the component fails to initialize silently and is muted.
- *
- * @param e The exception caught.
- * @param exceptionCause The exception cause.
- * @param true if the exception is handled and captured by this handler (and thus will not be
- * thrown anymore); false if the exception is not captured, in this case it will be probably
- * thrown again by the calling code.
- * @throws E If this handler throws the exception itself (it may add some cause or message).
- */
- false.
- */
- LoadingExceptionHandler NO_OP = new LoadingExceptionHandler() {
- @Override
- public boolean handleLoadingException(Exception e, boolean resourceAccessIssue) {
- return false;
- }
-
- @Override
- public int getLoadingMaxAttempts() {
- return 0;
- }
- };
-
- /**
- * Potentially handles and captures an exception that occurred while loading a resource.
- *
- * @param e The exception caught.
- * @param resourceAccessIssue true if the exception has been thrown because the resource could not
- * be accessed (missing or cannot be read); false if the resource has
- * been found and accessed but the error occurred while loading the resource
- * (invalid format, incomplete or corrupted).
- * @param true if the exception is handled and captured by this handler (and thus will not be
- * thrown anymore); false if the exception is not captured, in this case it will be probably
- * thrown again by the calling code.
- * @throws E If this handler throws the exception itself (it may add some cause or message).
- */
- true if the exception has been thrown
* because the resource could not be accessed (missing or cannot be read)
* or the config file is empty; false if the resource has
* been found and accessed but the error occurred while loading the resource
* (invalid format, incomplete or corrupted).
* @return The {@link ElevationProvider} to use if the exception is absorbed. If {@code null}
- * is returned, the {@link #NO_OP_ELEVATION_PROVIDER} is used but not cached in
- * the {@link ElevationProvider} cache.
+ * is returned, the {@link #NO_OP_ELEVATION_PROVIDER} is used but not cached in
+ * the {@link ElevationProvider} cache.
* @throws E If the exception is not absorbed.
*/
protected null.
- * @param excludedIds The ids of the excluded documents that should not appear in search results; can be null.
- */
- private Elevation createElevation(Collectionnull.
*/
- private Setnull.
+ * In configured order.
* @param excludedIds The ids of the excluded documents that should not appear in search results; can be null.
- * @param indexedValueProvider Provides the indexed value corresponding to a readable value..
* @param queryFieldName The field name to use to create query terms.
- * @param keepElevationPriority Whether to keep the elevation priority order.
*/
- private Elevation(Collectiontrue.
+ * When multiple docs are elevated, should their relative order be the order in the configuration file or should
+ * they be subject to whatever the sort criteria is? True by default.
*/
- String KEEP_ELEVATION_PRIORITY = "keepElevationPriority";
-}
+ String USE_CONFIGURED_ELEVATED_ORDER = "useConfiguredElevatedOrder";
+}
\ No newline at end of file