package com.plugtree.solradvert; /** * Copyright 2011 Plugtree LLC * * Licensed 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. */ import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.apache.lucene.search.Query; import org.apache.solr.common.SolrException; import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.util.NamedList; import org.apache.solr.core.SolrCore; import org.apache.solr.handler.component.ResponseBuilder; import org.apache.solr.handler.component.SearchComponent; import org.apache.solr.util.plugin.SolrCoreAware; import org.drools.KnowledgeBase; import org.drools.KnowledgeBaseFactory; import org.drools.builder.KnowledgeBuilder; import org.drools.builder.KnowledgeBuilderFactory; import org.drools.builder.ResourceType; import org.drools.command.Command; import org.drools.command.CommandFactory; import org.drools.io.ResourceFactory; import org.drools.runtime.StatelessKnowledgeSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.plugtree.solradvert.core.AdvertQuery; import com.plugtree.solradvert.core.AdvertQueryImpl; import com.plugtree.solradvert.core.QueryFactsCollector; import com.plugtree.solradvert.core.SchemaTool; import com.plugtree.solradvert.core.SolrXmlApplicationContext; /** * WARNING! This component must be put after the QueryComponent * in the components chain. * * @author salaboy */ public class AdvertComponent extends SearchComponent implements AdvertParams, SolrCoreAware { private static Logger logger = LoggerFactory.getLogger(AdvertComponent.class); private SolrXmlApplicationContext kcontext; private String kcontextFile; @Override public void init(@SuppressWarnings("rawtypes") NamedList args) { super.init(args); kcontextFile = (String)args.get(ADVERT_KNOWLEDGE_CONTEXT); if(kcontextFile==null) { kcontextFile = ADVERT_DEFAULT_KCONTEXT; } } @Override public void inform(SolrCore core) { // NOTE: ecj can't be used because it conflicts with the version // included in Jetty System.setProperty("drools.dialect.java.compiler", "JANINO"); loadKContext(core); } private void loadKContext(SolrCore core) { try { logger.info("Loading bean definitions from: " + kcontextFile); kcontext = new SolrXmlApplicationContext(core, kcontextFile); kcontext.refresh(); } catch(Exception ex) { throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, ex); } } private Collection<Object> getFacts(ResponseBuilder rb) { Collection<Object> facts = new ArrayList<Object>(); QueryFactsCollector factsCollector = new QueryFactsCollector(); // put the main query if(rb.getQuery()!=null) { factsCollector.collect(rb.getQuery(), facts); } // put all the filter queries if(rb.getFilters()!=null) { for(Query fq: rb.getFilters()) { factsCollector.collect(fq, facts); } } // put the AdvertQuery // this is only for backwards-compatibility, so old tests don't fail AdvertQuery aq = new AdvertQueryImpl(rb); facts.add(aq); // put the SchemaTool SchemaTool st = new SchemaTool(rb); facts.add(st); // put the response builder facts.add(rb); logger.debug("Collected facts: " + facts); return facts; } @Override public void prepare(final ResponseBuilder rb) throws IOException { SolrParams params = rb.req.getParams(); if(!params.getBool(ADVERT_COMPONENT_NAME, false)) { return; } logger.debug("Preparing Advert Component..."); try { // if advert.reload=true ---> reload spring's context if(params.getBool(ADVERT_RELOAD_RULES, false)) { logger.info("Reloading Spring context..."); if(kcontext!=null) { kcontext.refresh(); } else { loadKContext(rb.req.getCore()); } } String rules = params.get(ADVERT_RULES, ADVERT_DEFAULT_RULES); KnowledgeBase kbase = (KnowledgeBase) kcontext.getBean(rules); StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession(); List<Command<?>> cmds = new ArrayList<Command<?>>(); if(params.get(ADVERT_BATCH)!=null) { String extraCmdsBean = params.get(ADVERT_BATCH); List<Command<?>> extraCmds = (List<Command<?>>)kcontext.getBean(extraCmdsBean); cmds.addAll(extraCmds); logger.debug("Added " + extraCmds.size() + " extra command(s) to batch execution"); } Collection<?> facts = getFacts(rb); cmds.add(CommandFactory.newInsertElements(facts)); Command<?> batchCmd = CommandFactory.newBatchExecution(cmds); logger.debug("Executing Drools session"); ksession.execute(batchCmd); } catch(Exception ex) { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, ex); } } @Override public void process(ResponseBuilder rb) throws IOException { } @Override public String getName() { return "Solr Advert Component"; } @Override public String getDescription() { return "This component allows dynamic boosting and sorting based on Drools rules."; } @Override public String getSourceId() { return ""; } @Override public String getSource() { return "$URL: https://github.com/Salaboy/Solr-Advert/blob/queryIterator/solr-advert/src/main/java/com/plugtree/solradvert/AdvertComponent.java $"; } @Override public String getVersion() { return "1.0-SNAPSHOT"; } }