blob: 5248181b76bdd61c9d9c16dcd2a376f890ca844b [file] [log] [blame]
/*
* 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.handler.component;
import java.io.IOException;
import org.apache.solr.analytics.AnalyticsDriver;
import org.apache.solr.analytics.AnalyticsRequestManager;
import org.apache.solr.analytics.AnalyticsRequestParser;
import org.apache.solr.analytics.ExpressionFactory;
import org.apache.solr.analytics.stream.AnalyticsShardRequestManager;
import org.apache.solr.analytics.util.AnalyticsResponseHeadings;
import org.apache.solr.analytics.util.OldAnalyticsParams;
import org.apache.solr.analytics.util.OldAnalyticsRequestConverter;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.response.SolrQueryResponse;
/**
* Computes analytics requests.
*/
public class AnalyticsComponent extends SearchComponent {
public static final String COMPONENT_NAME = "analytics";
@Override
public void init(@SuppressWarnings({"rawtypes"})NamedList args) {
AnalyticsRequestParser.init();
}
@Override
public void prepare(ResponseBuilder rb) throws IOException {
// First check to see if there is an analytics request using the current format
String analyticsRequest = rb.req.getParams().get(AnalyticsRequestParser.analyticsParamName);
rb.setOlapAnalytics(false);
rb.setAnalytics(false);
boolean isDistributed = rb.isDistributed();
if (analyticsRequest != null) {
rb.setAnalytics(true);
rb.setAnalyticsRequestManager(
AnalyticsRequestParser.parse(
analyticsRequest,
new ExpressionFactory(rb.req.getSchema()), isDistributed));
}
// If there is no request in the current format, check for the old olap-style format
else if (rb.req.getParams().getBool(OldAnalyticsParams.OLD_ANALYTICS,false)) {
rb.setAnalyticsRequestManager(
AnalyticsRequestParser.parse(
OldAnalyticsRequestConverter.convert(rb.req.getParams()),
new ExpressionFactory(rb.req.getSchema()), isDistributed));
rb.setOlapAnalytics(true);
rb.setAnalytics(true);
}
if (rb.isAnalytics()) {
AnalyticsRequestManager reqManager = getAnalyticsRequestManager(rb);
// Check to see if the request is distributed
if (isDistributed) {
reqManager.sendShards = true;
reqManager.shardStream = new AnalyticsShardRequestManager(rb.req.getParams(), reqManager);
} else {
reqManager.sendShards = false;
rb.setNeedDocSet( true );
}
}
}
@Override
public void process(ResponseBuilder rb) throws IOException {
if (!rb.isAnalytics()) {
return;
}
AnalyticsRequestManager reqManager = getAnalyticsRequestManager(rb);
// Collect the data and generate a response
AnalyticsDriver.drive(reqManager, rb.req.getSearcher(), rb.getResults().docSet.getTopFilter(), rb.req);
if (rb.isOlapAnalytics()) {
rb.rsp.add(AnalyticsResponseHeadings.COMPLETED_OLD_HEADER, reqManager.createOldResponse());
} else {
rb.rsp.add(AnalyticsResponseHeadings.COMPLETED_HEADER, reqManager.createResponse());
}
rb.setAnalytics(false);
rb.setOlapAnalytics(false);
}
@Override
public int distributedProcess(ResponseBuilder rb) throws IOException {
if (!rb.isAnalytics() || rb.stage != ResponseBuilder.STAGE_EXECUTE_QUERY) {
return ResponseBuilder.STAGE_DONE;
}
AnalyticsRequestManager reqManager = getAnalyticsRequestManager(rb);
if (!reqManager.sendShards){
return ResponseBuilder.STAGE_DONE;
}
// Send out a request to each shard and merge the responses into our AnalyticsRequestManager
reqManager.shardStream.sendRequests(rb.req.getCore().getCoreDescriptor().getCollectionName(),
rb.req.getCore().getCoreContainer().getZkController().getZkServerAddress());
reqManager.sendShards = false;
return ResponseBuilder.STAGE_DONE;
}
@Override
public void modifyRequest(ResponseBuilder rb, SearchComponent who, ShardRequest sreq) {
// We don't want the shard requests to compute analytics, since we send
// separate requests for that in distributedProcess() to the AnalyticsHandler
sreq.params.remove(AnalyticsRequestParser.analyticsParamName);
sreq.params.remove(OldAnalyticsParams.OLD_ANALYTICS);
super.modifyRequest(rb, who, sreq);
}
@Override
public void handleResponses(ResponseBuilder rb, ShardRequest sreq) {
// NO-OP since analytics shard responses are handled through the AnalyticsResponseParser
super.handleResponses(rb, sreq);
}
@Override
public void finishStage(ResponseBuilder rb) {
if (rb.isAnalytics() && rb.stage == ResponseBuilder.STAGE_GET_FIELDS) {
AnalyticsRequestManager reqManager = getAnalyticsRequestManager(rb);
// Generate responses from the merged shard data
if (rb.isOlapAnalytics()) {
rb.rsp.add(AnalyticsResponseHeadings.COMPLETED_OLD_HEADER, reqManager.createOldResponse());
} else {
rb.rsp.add(AnalyticsResponseHeadings.COMPLETED_HEADER, reqManager.createResponse());
}
if (reqManager.isPartialResults()) {
rb.rsp.getResponseHeader().asShallowMap().put(SolrQueryResponse.RESPONSE_HEADER_PARTIAL_RESULTS_KEY,true);
}
}
super.finishStage(rb);
}
@Override
public String getName() {
return COMPONENT_NAME;
}
@Override
public String getDescription() {
return "Perform analytics";
}
private AnalyticsRequestManager getAnalyticsRequestManager(ResponseBuilder rb) {
return (AnalyticsRequestManager)rb.getAnalyticsRequestManager();
}
/*@Override
public NamedList getStatistics() {
return analyticsCollector.getStatistics();
}*/
}