1010
1111import static org .opensearch .plugin .insights .rules .model .SearchQueryRecord .DEFAULT_TOP_N_QUERY_MAP ;
1212import static org .opensearch .plugin .insights .settings .QueryCategorizationSettings .SEARCH_QUERY_METRICS_ENABLED_SETTING ;
13+ import static org .opensearch .plugin .insights .settings .QueryInsightsSettings .TOP_N_QUERIES_EXCLUDED_INDICES ;
1314import static org .opensearch .plugin .insights .settings .QueryInsightsSettings .TOP_N_QUERIES_GROUPING_FIELD_NAME ;
1415import static org .opensearch .plugin .insights .settings .QueryInsightsSettings .TOP_N_QUERIES_GROUPING_FIELD_TYPE ;
1516import static org .opensearch .plugin .insights .settings .QueryInsightsSettings .TOP_N_QUERIES_GROUP_BY ;
2223import java .util .List ;
2324import java .util .Locale ;
2425import java .util .Map ;
26+ import java .util .Optional ;
27+ import java .util .Set ;
2528import java .util .concurrent .TimeUnit ;
29+ import java .util .regex .Pattern ;
30+ import java .util .stream .Collectors ;
2631import org .apache .logging .log4j .LogManager ;
2732import org .apache .logging .log4j .Logger ;
2833import org .opensearch .action .search .SearchPhaseContext ;
3237import org .opensearch .action .search .SearchTask ;
3338import org .opensearch .cluster .service .ClusterService ;
3439import org .opensearch .common .inject .Inject ;
40+ import org .opensearch .core .index .Index ;
3541import org .opensearch .core .tasks .resourcetracker .TaskResourceInfo ;
3642import org .opensearch .plugin .insights .core .metrics .OperationalMetric ;
3743import org .opensearch .plugin .insights .core .metrics .OperationalMetricsCounter ;
4248import org .opensearch .plugin .insights .rules .model .MetricType ;
4349import org .opensearch .plugin .insights .rules .model .SearchQueryRecord ;
4450import org .opensearch .plugin .insights .settings .QueryInsightsSettings ;
51+ import org .opensearch .search .builder .SearchSourceBuilder ;
4552import org .opensearch .tasks .Task ;
53+ import reactor .util .annotation .NonNull ;
4654
4755/**
4856 * The listener for query insights services.
@@ -58,6 +66,7 @@ public final class QueryInsightsListener extends SearchRequestOperationsListener
5866 private boolean groupingFieldNameEnabled ;
5967 private boolean groupingFieldTypeEnabled ;
6068 private final QueryShapeGenerator queryShapeGenerator ;
69+ private Set <Pattern > excludedIndicesPattern ;
6170
6271 /**
6372 * Constructor for QueryInsightsListener
@@ -134,6 +143,15 @@ public QueryInsightsListener(
134143 this .queryInsightsService .validateMaximumGroups (clusterService .getClusterSettings ().get (TOP_N_QUERIES_MAX_GROUPS_EXCLUDING_N ));
135144 this .queryInsightsService .setMaximumGroups (clusterService .getClusterSettings ().get (TOP_N_QUERIES_MAX_GROUPS_EXCLUDING_N ));
136145
146+ clusterService .getClusterSettings ()
147+ .addSettingsUpdateConsumer (
148+ QueryInsightsSettings .TOP_N_QUERIES_EXCLUDED_INDICES ,
149+ this ::setExcludedIndices ,
150+ this ::validateExcludedIndices
151+ );
152+ validateExcludedIndices (clusterService .getClusterSettings ().get (TOP_N_QUERIES_EXCLUDED_INDICES ));
153+ setExcludedIndices (clusterService .getClusterSettings ().get (TOP_N_QUERIES_EXCLUDED_INDICES ));
154+
137155 // Internal settings for grouping attributes
138156 clusterService .getClusterSettings ().addSettingsUpdateConsumer (TOP_N_QUERIES_GROUPING_FIELD_NAME , this ::setGroupingFieldNameEnabled );
139157 setGroupingFieldNameEnabled (clusterService .getClusterSettings ().get (TOP_N_QUERIES_GROUPING_FIELD_NAME ));
@@ -147,6 +165,13 @@ public QueryInsightsListener(
147165 setSearchQueryMetricsEnabled (clusterService .getClusterSettings ().get (SEARCH_QUERY_METRICS_ENABLED_SETTING ));
148166 }
149167
168+ private void setExcludedIndices (List <String > excludedIndices ) {
169+ this .excludedIndicesPattern = excludedIndices .stream ()
170+ .map (index -> index .contains ("*" ) ? index .replace ("*" , ".*" ) : index )
171+ .map (Pattern ::compile )
172+ .collect (Collectors .toSet ());
173+ }
174+
150175 /**
151176 * Enable or disable top queries insights collection for {@link MetricType}.
152177 * This function will enable or disable the corresponding listeners
@@ -221,9 +246,35 @@ public void onRequestFailure(final SearchPhaseContext context, final SearchReque
221246 constructSearchQueryRecord (context , searchRequestContext );
222247 }
223248
224- private void constructSearchQueryRecord ( final SearchPhaseContext context , final SearchRequestContext searchRequestContext ) {
249+ private boolean skipSearchRequest ( final SearchRequestContext searchRequestContext ) {
225250 // Skip profile queries
226- if (searchRequestContext .getRequest ().source ().profile ()) {
251+ if (Optional .ofNullable (searchRequestContext )
252+ .map (SearchRequestContext ::getRequest )
253+ .map (SearchRequest ::source )
254+ .map (SearchSourceBuilder ::profile )
255+ .orElse (false )) {
256+ return true ;
257+ }
258+
259+ if (excludedIndicesPattern .isEmpty ()) {
260+ return false ;
261+ }
262+
263+ return Optional .ofNullable (searchRequestContext )
264+ .map (SearchRequestContext ::getSuccessfulSearchShardIndices )
265+ .map (indices -> indices .stream ().map (Index ::getName ).anyMatch (this ::matchedExcludedIndices ))
266+ .orElse (false );
267+ }
268+
269+ private boolean matchedExcludedIndices (String indexName ) {
270+ if (indexName == null || excludedIndicesPattern == null ) {
271+ return false ;
272+ }
273+ return excludedIndicesPattern .stream ().anyMatch (pattern -> pattern .matcher (indexName ).matches ());
274+ }
275+
276+ private void constructSearchQueryRecord (final SearchPhaseContext context , final SearchRequestContext searchRequestContext ) {
277+ if (skipSearchRequest (searchRequestContext )) {
227278 return ;
228279 }
229280
@@ -307,4 +358,22 @@ private void constructSearchQueryRecord(final SearchPhaseContext context, final
307358 }
308359 }
309360
361+ /**
362+ * Validate the index name for excluded indices
363+ * @param excludedIndices list of index to validate
364+ */
365+ public void validateExcludedIndices (@ NonNull List <String > excludedIndices ) {
366+ for (String index : excludedIndices ) {
367+ if (index == null ) {
368+ throw new IllegalArgumentException ("Excluded index name cannot be null." );
369+ }
370+ if (index .isBlank ()) {
371+ throw new IllegalArgumentException ("Excluded index name cannot be blank." );
372+ }
373+ if (index .chars ().anyMatch (Character ::isUpperCase )) {
374+ throw new IllegalArgumentException ("Index name must be lowercase." );
375+ }
376+ }
377+ }
378+
310379}
0 commit comments