/* * 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.solr.analytics.accumulator; import java.io.IOException; import java.lang.invoke.MethodHandles; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Set; import java.util.function.Supplier; import org.apache.lucene.index.LeafReaderContext; import org.apache.solr.analytics.expression.Expression; import org.apache.solr.analytics.expression.ExpressionFactory; import org.apache.solr.analytics.request.AnalyticsRequest; import org.apache.solr.analytics.request.ExpressionRequest; import org.apache.solr.analytics.statistics.StatsCollector; import org.apache.solr.analytics.statistics.StatsCollectorSupplierFactory; import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException.ErrorCode; import org.apache.solr.common.util.NamedList; import org.apache.solr.search.DocSet; import org.apache.solr.search.SolrIndexSearcher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A <code>BasicAccumulator</code> manages the ValueCounters and Expressions without regard to Facets. */ public class BasicAccumulator extends ValueAccumulator { private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); protected final SolrIndexSearcher searcher; protected final AnalyticsRequest request; protected final DocSet docs; protected final Supplier<StatsCollector[]> statsCollectorArraySupplier; protected final StatsCollector[] statsCollectors; protected final Expression[] expressions; protected final String[] expressionNames; protected final String[] expressionStrings; protected final Set<String> hiddenExpressions; protected LeafReaderContext context = null; public BasicAccumulator(SolrIndexSearcher searcher, DocSet docs, AnalyticsRequest request) throws IOException { this.searcher = searcher; this.docs = docs; this.request = request; final List<ExpressionRequest> exRequests = new ArrayList<ExpressionRequest>(request.getExpressions()); // make a copy here Collections.sort(exRequests); log.info("Processing request '"+request.getName()+"'"); statsCollectorArraySupplier = StatsCollectorSupplierFactory.create(searcher.getSchema(), exRequests); statsCollectors = statsCollectorArraySupplier.get(); int size = exRequests.size(); expressionNames = new String[size]; expressionStrings = new String[size]; int count = 0; for (ExpressionRequest expRequest : exRequests) { expressionNames[count] = expRequest.getName(); expressionStrings[count++] = expRequest.getExpressionString(); } expressions = makeExpressions(statsCollectors); hiddenExpressions = request.getHiddenExpressions(); } @Override protected void doSetNextReader(LeafReaderContext context) throws IOException { this.context = context; for (StatsCollector counter : statsCollectors) { counter.setNextReader(context); } } public static BasicAccumulator create(SolrIndexSearcher searcher, DocSet docs, AnalyticsRequest request) throws IOException { return new BasicAccumulator(searcher,docs,request); } /** * Passes the documents on to the {@link StatsCollector}s to be collected. * @param doc Document to collect from */ @Override public void collect(int doc) throws IOException { for (StatsCollector statsCollector : statsCollectors) { statsCollector.collect(doc); } } @Override public void compute() { for (StatsCollector statsCollector : statsCollectors) { statsCollector.compute(); } } public NamedList<?> export(){ NamedList<Object> base = new NamedList<>(); for (int count = 0; count < expressions.length; count++) { if (!hiddenExpressions.contains(expressionNames[count])) { base.add(expressionNames[count], expressions[count].getValue()); } } return base; } /** * Builds an array of Expressions with the given list of counters * @param statsCollectors the stats collectors * @return The array of Expressions */ public Expression[] makeExpressions(StatsCollector[] statsCollectors) { Expression[] expressions = new Expression[expressionStrings.length]; for (int count = 0; count < expressionStrings.length; count++) { expressions[count] = ExpressionFactory.create(expressionStrings[count], statsCollectors); } return expressions; } /** * Returns the value of an expression to use in a field or query facet. * @param expressionName the name of the expression * @return String String representation of pivot value */ @SuppressWarnings({ "deprecation", "rawtypes" }) public String getResult(String expressionName) { for (int count = 0; count < expressionNames.length; count++) { if (expressionName.equals(expressionNames[count])) { Comparable value = expressions[count].getValue(); if (value.getClass().equals(Date.class)) { return ((Date)value).toInstant().toString(); } else { return value.toString(); } } } throw new SolrException(ErrorCode.BAD_REQUEST, "Pivot expression "+expressionName+" not found."); } /** * Used for JMX stats collecting. Counts the number of stats requests * @return number of unique stats collectors */ public long getNumStatsCollectors() { return statsCollectors.length; } /** * Used for JMX stats collecting. Counts the number of queries in all query facets * @return number of queries requested in all query facets. */ public long getNumQueries() { return 0l; } @Override public boolean needsScores() { return true; // TODO: is this true? } }