Author: ssmiweve
Date: 2009-07-22 14:03:27 +0200 (Wed, 22 Jul 2009)
New Revision: 7259

Added:
   
branches/2.18/generic.sesam/search-command-config/src/main/java/no/sesat/search/mode/config/CorrectingSolrCommandConfig.java
   
branches/2.18/generic.sesam/search-command-control/default/src/main/java/no/sesat/search/mode/command/CorrectingSolrSearchCommand.java
   
branches/2.18/search-command-config-spi/src/main/java/no/sesat/search/mode/config/CorrectingCommandConfig.java
   
branches/2.18/search-command-control-spi/src/main/java/no/sesat/search/mode/command/CorrectingSearchCommand.java
   
branches/2.18/search-command-control-spi/src/main/java/no/sesat/search/mode/command/CorrectingSearchCommandUtility.java
Modified:
   
branches/2.18/generic.sesam/search-command-config/src/main/java/no/sesat/search/mode/config/CorrectingFast4CommandConfig.java
   
branches/2.18/generic.sesam/search-command-control/fast/src/main/java/no/sesat/search/mode/command/CorrectingFast4SearchCommand.java
Log:
http://sesat.no/218-upgrade.html#2.18Upgrade-CorrectingSearchCommandbehaviourformalised%2522thJun%2529
Refactor out the Correcting search behaviour from CorrectingFast4SearchCommand 
into it's own interface  CorrectingSearchCommand
 and moving a lot of the functionality into the helper utility 
CorrectingSearchCommandUtility
Also implement this behaviour on top of the SolrSearchCommand w/ 
CorrectingSolrSearchCommand.


Modified: 
branches/2.18/generic.sesam/search-command-config/src/main/java/no/sesat/search/mode/config/CorrectingFast4CommandConfig.java
===================================================================
--- 
branches/2.18/generic.sesam/search-command-config/src/main/java/no/sesat/search/mode/config/CorrectingFast4CommandConfig.java
       2009-07-21 15:16:20 UTC (rev 7258)
+++ 
branches/2.18/generic.sesam/search-command-config/src/main/java/no/sesat/search/mode/config/CorrectingFast4CommandConfig.java
       2009-07-22 12:03:27 UTC (rev 7259)
@@ -1,5 +1,5 @@
 /*
- * Copyright (2005-2008) Schibsted ASA
+ * Copyright (2005-2009) Schibsted ASA
  * This file is part of SESAT.
  *
  *   SESAT is free software: you can redistribute it and/or modify
@@ -20,7 +20,6 @@
 
 
 import no.sesat.search.mode.config.CommandConfig.Controller;
-import org.apache.log4j.Logger;
 
 
 /** Configure a Correcting Fast 4 search command.
@@ -28,16 +27,18 @@
  * @version <tt>$Id$</tt>
  */
 @Controller("CorrectingFast4SearchCommand")
-public class CorrectingFast4CommandConfig extends FastCommandConfig {
+public class CorrectingFast4CommandConfig extends FastCommandConfig implements 
CorrectingCommandConfig{
 
     //private static final Logger LOG = 
Logger.getLogger(CorrectingFast4CommandConfig.class);
 
     private int correctingLimit = 1;
 
+    @Override
     public void setCorrectingLimit(final int correctingLimit){
         this.correctingLimit = correctingLimit;
     }
 
+    @Override
     public int getCorrectingLimit(){
         return correctingLimit;
     }

Added: 
branches/2.18/generic.sesam/search-command-config/src/main/java/no/sesat/search/mode/config/CorrectingSolrCommandConfig.java
===================================================================
--- 
branches/2.18/generic.sesam/search-command-config/src/main/java/no/sesat/search/mode/config/CorrectingSolrCommandConfig.java
                                (rev 0)
+++ 
branches/2.18/generic.sesam/search-command-config/src/main/java/no/sesat/search/mode/config/CorrectingSolrCommandConfig.java
        2009-07-22 12:03:27 UTC (rev 7259)
@@ -0,0 +1,45 @@
+/*
+ * Copyright (2005-2009) Schibsted ASA
+ * This file is part of SESAT.
+ *
+ *   SESAT is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU Affero General Public License as published 
by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   SESAT is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Affero General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Affero General Public License
+ *   along with SESAT.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package no.sesat.search.mode.config;
+
+
+import no.sesat.search.mode.config.CommandConfig.Controller;
+
+
+/** Configure a Correcting Solr search command.
+ *
+ * @version <tt>$Id$</tt>
+ */
+...@controller("CorrectingSolrSearchCommand")
+public class CorrectingSolrCommandConfig extends SolrCommandConfig implements 
CorrectingCommandConfig{
+
+    //private static final Logger LOG = 
Logger.getLogger(CorrectingSolrCommandConfig.class);
+
+    private int correctingLimit = 1;
+
+    @Override
+    public void setCorrectingLimit(final int correctingLimit){
+        this.correctingLimit = correctingLimit;
+    }
+
+    @Override
+    public int getCorrectingLimit(){
+        return correctingLimit;
+    }
+}


Property changes on: 
branches/2.18/generic.sesam/search-command-config/src/main/java/no/sesat/search/mode/config/CorrectingSolrCommandConfig.java
___________________________________________________________________
Added: svn:keywords
   + Id

Added: 
branches/2.18/generic.sesam/search-command-control/default/src/main/java/no/sesat/search/mode/command/CorrectingSolrSearchCommand.java
===================================================================
--- 
branches/2.18/generic.sesam/search-command-control/default/src/main/java/no/sesat/search/mode/command/CorrectingSolrSearchCommand.java
                              (rev 0)
+++ 
branches/2.18/generic.sesam/search-command-control/default/src/main/java/no/sesat/search/mode/command/CorrectingSolrSearchCommand.java
      2009-07-22 12:03:27 UTC (rev 7259)
@@ -0,0 +1,129 @@
+/* Copyright (2009) Schibsted ASA
+ * This file is part of SESAT.
+ *
+ *   SESAT is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU Affero General Public License as published 
by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   SESAT is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Affero General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Affero General Public License
+ *   along with SESAT.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package no.sesat.search.mode.command;
+
+
+import no.sesat.search.mode.config.CorrectingSolrCommandConfig;
+import no.sesat.search.query.Query;
+import no.sesat.search.result.ResultItem;
+import no.sesat.search.result.ResultList;
+import org.apache.log4j.Logger;
+
+/** Supplements CorrectingSearchCommand behaviour to the SolrSearchCommand.
+ *
+ * correctQuery(..) delegates to 
CorrectingSearchCommandUtility.correctQueryFromSpellingSuggestions(results, q)
+ *  and the spelling suggestions returned from the solr index.
+ *
+ * @version $Id$
+ */
+public class CorrectingSolrSearchCommand extends SolrSearchCommand implements 
CorrectingSearchCommand {
+
+    // Constants -----------------------------------------------------
+
+    private static final Logger LOG = 
Logger.getLogger(CorrectingSolrSearchCommand.class);
+
+    // Attributes ----------------------------------------------------
+
+    private int correctionCount = 0;
+
+    // XXX couldn't we re-use functionality given by overriding 
AbstractSearchCommand.getQuery()
+    private ReconstructedQuery correctedQuery;
+
+    private volatile boolean inCall = false;
+
+    // Static --------------------------------------------------------
+
+    // Constructors --------------------------------------------------
+
+    /** Creates a new instance of CorrectionFastSearchCommand.
+     *
+     * @param cxt Search command context.
+     */
+    public CorrectingSolrSearchCommand(final Context cxt) {
+        super(cxt);
+    }
+
+    // Public --------------------------------------------------------
+
+    @Override
+    public ResultList<ResultItem> call() {
+
+        final boolean wasInCall = inCall;
+        try{
+            inCall = true;
+
+            return wasInCall
+                    ? super.call()
+                    : CorrectingSearchCommandUtility.doCall(this, context);
+        }finally{
+            inCall = false;
+        }
+    }
+
+    @Override
+    public final Query getQuery() {
+        return correctedQuery != null ? correctedQuery.getQuery() : 
super.getQuery();
+    }
+
+    @Override
+    public CorrectingSolrCommandConfig getSearchConfiguration() {
+        return (CorrectingSolrCommandConfig)super.getSearchConfiguration();
+    }
+
+    @Override
+    public final int getCorrectionCount(){
+        return correctionCount;
+    }
+
+    @Override
+    public final void setCorrectionCount(final int count){
+        this.correctionCount = count;
+    }
+
+    @Override
+    public void setCorrectedQuery(final String correctedQuery) {
+
+        setCorrectedQuery(createQuery(correctedQuery));
+        initialiseTransformedTerms(getQuery());
+    }
+
+    @Override
+    public String correctQuery(final ResultList<ResultItem> results, String q) 
{
+
+        return 
CorrectingSearchCommandUtility.correctQueryFromSpellingSuggestions(results, q);
+    }
+
+    @Override
+    public CorrectingSearchCommand initialiseNewCommand(final  
CorrectingSearchCommand command){
+        return command;
+    }
+
+    // Package protected ---------------------------------------------
+
+    // Protected -----------------------------------------------------
+
+
+    protected final void setCorrectedQuery(final ReconstructedQuery query){
+
+        this.correctedQuery = query;
+    }
+
+    // private -------------------------------------------------------
+
+    // Inner classes -------------------------------------------------
+
+}


Property changes on: 
branches/2.18/generic.sesam/search-command-control/default/src/main/java/no/sesat/search/mode/command/CorrectingSolrSearchCommand.java
___________________________________________________________________
Added: svn:keywords
   + Id

Modified: 
branches/2.18/generic.sesam/search-command-control/fast/src/main/java/no/sesat/search/mode/command/CorrectingFast4SearchCommand.java
===================================================================
--- 
branches/2.18/generic.sesam/search-command-control/fast/src/main/java/no/sesat/search/mode/command/CorrectingFast4SearchCommand.java
        2009-07-21 15:16:20 UTC (rev 7258)
+++ 
branches/2.18/generic.sesam/search-command-control/fast/src/main/java/no/sesat/search/mode/command/CorrectingFast4SearchCommand.java
        2009-07-22 12:03:27 UTC (rev 7259)
@@ -1,4 +1,4 @@
-/* Copyright (2006-2008) Schibsted ASA
+/* Copyright (2006-2009) Schibsted ASA
  * This file is part of SESAT.
  *
  *   SESAT is free software: you can redistribute it and/or modify
@@ -28,22 +28,14 @@
 import no.sesat.search.result.ResultList;
 import no.sesat.search.result.WeightedSuggestion;
 
-/**
- * This class can be extended to get the following behaviour.
+/** Supplements CorrectingSearchCommand behaviour to the Fast4SearchCommand.
  *
- * If the execution of the search command does not return any hits and if there
- * is an query available, correct the query and rerun the command.
+ * correctQuery(..) delegates to 
CorrectingSearchCommandUtility.correctQueryFromSpellingSuggestions(results, q)
+ *  and the spelling suggestions returned from the fast index.
  *
- * The default implementation looks at the hitCount == 0 and what relevant 
queries are available.
- *
- * <b>Performance improvement</b> can be gained by overridding 
correctQuery(string) and calling
- * createQuery(string, false) so that another round evaluation is disabled.
- *
- * @XXX refactor out this functionality to a search command functor class.
- *
  * @version $Id$
  */
-public abstract class CorrectingFast4SearchCommand extends Fast4SearchCommand {
+public class CorrectingFast4SearchCommand extends Fast4SearchCommand 
implements CorrectingSearchCommand {
 
     // Constants -----------------------------------------------------
 
@@ -54,9 +46,9 @@
     private static final Logger LOG = 
Logger.getLogger(CorrectingFast4SearchCommand.class);
 
     // Attributes ----------------------------------------------------
+    private volatile boolean inCall = false;
 
     private int correctionCount = 0;
-    private final Context cxt;
 
     // XXX couldn't we re-use functionality given by overriding 
AbstractSearchCommand.getQuery()
     private ReconstructedQuery correctedQuery;
@@ -71,7 +63,6 @@
      */
     public CorrectingFast4SearchCommand(final Context cxt) {
         super(cxt);
-        this.cxt = cxt;
     }
 
     // Public --------------------------------------------------------
@@ -84,48 +75,14 @@
     @Override
     public ResultList<ResultItem> call() {
 
-        ResultList<ResultItem> result = super.call();
-
-        // TODO Consider moving the isCorrectionEnabled() call after the
-        // correction has been made and then discarding the result
-        // should the call return false.
-        // Sub classes might not know if the corrected query should be used
-        // until after the query has been run. or at least not after a token
-        // evaluation has been run on the corrected query.
-        if (getCorrectionCount() < 
getSearchConfiguration().getCorrectingLimit()) {
-
-            // Correct query and parse the resulting query string.
-            final String oldQuery = datamodel.getQuery().getString();
-            final String newQuery = correctQuery(result, oldQuery);
-
-            if(!oldQuery.equalsIgnoreCase(newQuery)){
-
-                try {
-
-                    // Create a new command
-                    final CorrectingFast4SearchCommand c = createCommand(cxt);
-
-                    // and update it to use the corrected query
-                    c.setCorrectedQuery(newQuery);
-                    c.initialiseTransformedTerms(c.getQuery());
-
-                    // now execute the command like normal
-                    result = c.call();
-
-                    // update this command's query to mirror the corrected 
command
-                    
datamodel.getSearch(getSearchConfiguration().getId()).setQuery(
-                            
datamodel.getSearch(c.getSearchConfiguration().getId()).getQuery());
-
-                    // how many times correction has taken place is useful 
information
-                    result = result.addObjectField(CORRECTION_COUNT, 
c.correctionCount);
-
-                } catch (Exception ex) {
-                    LOG.error(ERR_CANNOT_CREATE_COMMAND, ex);
-                }
-            }
+        try{
+            inCall = true;
+            return inCall
+                    ? super.call()
+                    : CorrectingSearchCommandUtility.doCall(this, context);
+        }finally{
+            inCall = false;
         }
-
-        return result;
     }
 
     @Override
@@ -133,53 +90,37 @@
         return (CorrectingFast4CommandConfig)super.getSearchConfiguration();
     }
 
-    // Package protected ---------------------------------------------
+    @Override
+    public String correctQuery(final ResultList<ResultItem> results, String q) 
{
 
-    // Protected -----------------------------------------------------
+        return 
CorrectingSearchCommandUtility.correctQueryFromSpellingSuggestions(results, q);
+    }
 
-    protected CorrectingFast4SearchCommand createCommand(final 
SearchCommand.Context cmdCxt) throws Exception {
+    @Override
+    public final int getCorrectionCount(){
+        return correctionCount;
+    }
 
-        final Class<? extends CorrectingFast4SearchCommand> clazz = getClass();
-        final Constructor<? extends CorrectingFast4SearchCommand> con = 
clazz.getConstructor(Context.class);
-
-        final CorrectingFast4SearchCommand command = con.newInstance(cmdCxt);
-
-        // note the number of times correction has occurred so far
-        command.correctionCount = getCorrectionCount() + 1;
-        return command;
+    @Override
+    public final void setCorrectionCount(final int count){
+        this.correctionCount = count;
     }
 
-    protected String correctQuery(
-            final ResultList<ResultItem> results,
-            String q) {
+    @Override
+    public void setCorrectedQuery(final String correctedQuery) {
 
-        if(0 == results.getHitCount()){
-
-            final Map<String, List<WeightedSuggestion>> suggestions
-                    = 
((BasicResultList<?>)results).getSpellingSuggestionsMap();
-
-            // Query suggestions is returned in lowercase from Fast, including 
the keys that
-            // maybe had mixed case. Lowers the case first to make the 
replacement work.
-            q = q.toLowerCase();
-
-            for (final List<WeightedSuggestion> suggestionList : 
suggestions.values()) {
-                for (final WeightedSuggestion s : suggestionList) {
-                    q = q.replaceAll(s.getOriginal(), s.getSuggestion());
-                }
-            }
-        }
-
-        return q;
+        setCorrectedQuery(createQuery(correctedQuery));
+        initialiseTransformedTerms(getQuery());
     }
 
-    protected final int getCorrectionCount(){
-        return correctionCount;
+    @Override
+    public CorrectingSearchCommand initialiseNewCommand(final  
CorrectingSearchCommand command){
+        return command;
     }
 
-    protected void setCorrectedQuery(final String correctedQuery) {
+    // Package protected ---------------------------------------------
 
-        setCorrectedQuery(createQuery(correctedQuery));
-    }
+    // Protected -----------------------------------------------------
 
     protected final void setCorrectedQuery(final ReconstructedQuery query){
 

Added: 
branches/2.18/search-command-config-spi/src/main/java/no/sesat/search/mode/config/CorrectingCommandConfig.java
===================================================================
--- 
branches/2.18/search-command-config-spi/src/main/java/no/sesat/search/mode/config/CorrectingCommandConfig.java
                              (rev 0)
+++ 
branches/2.18/search-command-config-spi/src/main/java/no/sesat/search/mode/config/CorrectingCommandConfig.java
      2009-07-22 12:03:27 UTC (rev 7259)
@@ -0,0 +1,40 @@
+/* Copyright (2009) Schibsted ASA
+ * This file is part of SESAT.
+ *
+ *   SESAT is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU Affero General Public License as published 
by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   SESAT is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Affero General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Affero General Public License
+ *   along with SESAT.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package no.sesat.search.mode.config;
+
+/** Extended behaviour to any SearchCommand that allows it to re-run searches 
modifying the query each time
+ * until the result list is desirable.
+ * The search command itself is not re-run but rather a new instance of the 
search command is constructed and executed.
+ * It is expected that the correctionCount is passed on from old command to 
the new.
+ *
+ * Any implementation must be able to correctQuery(..) if it wishes the 
command to run again. If this method returns
+ * the same query string then the command is not executed again and the 
current result list deemed desirable.
+ * This decision is also influenced by 
CorrectinCommandConfig.getCorrectingLimit.
+ *
+ * CorrectingSearchCommandUtility.correctQueryFromSpellingSuggestions(..) 
provides a helping implementation
+ * that the correctQuery method can delegate to. It relies on the presense of 
SpellingSuggestions in the result list.
+ *
+ * CorrectingSearchCommandUtility.doCall(..) is a helper functor method to 
handle the looping execution process.
+ * See CorrectingSolrSearchCommand.call(..) for example usage of it.
+ *
+ * @see CorrectingSearchCommand
+ * @version $Id$
+ */
+public interface CorrectingCommandConfig extends SearchConfiguration{
+    void setCorrectingLimit(int correctingLimit);
+    int getCorrectingLimit();
+}


Property changes on: 
branches/2.18/search-command-config-spi/src/main/java/no/sesat/search/mode/config/CorrectingCommandConfig.java
___________________________________________________________________
Added: svn:keywords
   + Id

Added: 
branches/2.18/search-command-control-spi/src/main/java/no/sesat/search/mode/command/CorrectingSearchCommand.java
===================================================================
--- 
branches/2.18/search-command-control-spi/src/main/java/no/sesat/search/mode/command/CorrectingSearchCommand.java
                            (rev 0)
+++ 
branches/2.18/search-command-control-spi/src/main/java/no/sesat/search/mode/command/CorrectingSearchCommand.java
    2009-07-22 12:03:27 UTC (rev 7259)
@@ -0,0 +1,55 @@
+/* Copyright (2009) Schibsted ASA
+ * This file is part of SESAT.
+ *
+ *   SESAT is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU Affero General Public License as published 
by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   SESAT is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Affero General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Affero General Public License
+ *   along with SESAT.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package no.sesat.search.mode.command;
+
+import no.sesat.search.mode.config.CorrectingCommandConfig;
+import no.sesat.search.result.ResultItem;
+import no.sesat.search.result.ResultList;
+
+/** @see CorrectingCommandConfig
+ *
+ * @version $Id$
+ */
+public interface CorrectingSearchCommand  extends SearchCommand{
+        @Override
+        CorrectingCommandConfig getSearchConfiguration();
+
+        /** Allows extra initialisation of any newly constructed search 
command before it is run.
+         * For example additional fields to correctionCount can be passed from 
old command to new.
+         *
+         * Normal to be a blank implementation simply returning the argument.
+         *
+         * @param command newly created search command before it is run.
+         * @return the newly created command but with extra initialisation 
performed.
+         */
+        CorrectingSearchCommand initialiseNewCommand(CorrectingSearchCommand 
command);
+
+        /**
+         * Any implementation must be able to correctQuery(..) if it wishes 
the command to run again. If this method returns
+         * the same query string then the command is not executed again and 
the current result list deemed desirable.
+         * This decision is also influenced by 
CorrectinCommandConfig.getCorrectingLimit.
+         *
+         * @param results the result list of the previous executed command
+         * @param q the existing query string
+         * @return the same query string if result list is desired, an altered 
query string if command should 'correct'.
+         */
+        String correctQuery(ResultList<ResultItem> results, String q);
+        void setCorrectedQuery(String correctedQuery);
+        int getCorrectionCount();
+        void setCorrectionCount(int count);
+
+}


Property changes on: 
branches/2.18/search-command-control-spi/src/main/java/no/sesat/search/mode/command/CorrectingSearchCommand.java
___________________________________________________________________
Added: svn:keywords
   + Id

Added: 
branches/2.18/search-command-control-spi/src/main/java/no/sesat/search/mode/command/CorrectingSearchCommandUtility.java
===================================================================
--- 
branches/2.18/search-command-control-spi/src/main/java/no/sesat/search/mode/command/CorrectingSearchCommandUtility.java
                             (rev 0)
+++ 
branches/2.18/search-command-control-spi/src/main/java/no/sesat/search/mode/command/CorrectingSearchCommandUtility.java
     2009-07-22 12:03:27 UTC (rev 7259)
@@ -0,0 +1,185 @@
+/* Copyright (2009) Schibsted ASA
+ * This file is part of SESAT.
+ *
+ *   SESAT is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU Affero General Public License as published 
by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   SESAT is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Affero General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Affero General Public License
+ *   along with SESAT.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package no.sesat.search.mode.command;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.List;
+import java.util.Map;
+import no.sesat.search.mode.command.SearchCommand.Context;
+import no.sesat.search.result.BasicResultList;
+import no.sesat.search.result.ResultItem;
+import no.sesat.search.result.ResultList;
+import no.sesat.search.result.WeightedSuggestion;
+import org.apache.log4j.Logger;
+
+/**
+ * Utility class to help implement CorrectingSearchCommand.
+ *
+ * If the execution of the search command does not return any hits and if there
+ * is an query available, correct the query and rerun the command.
+ *
+ * <b>Performance improvement</b> can be gained by overridding 
correctQuery(string) and calling
+ * createQuery(string, false) so that another round evaluation is disabled.
+ *
+ * @version $Id$
+ */
+public final class CorrectingSearchCommandUtility {
+
+    // Constants -----------------------------------------------------
+
+    public static final String CORRECTION_COUNT = "correctionCount";
+
+    private static final Logger LOG = 
Logger.getLogger(CorrectingSearchCommandUtility.class);
+    private static final String ERR_CANNOT_CREATE_COMMAND = "Unable to create 
command to rerun.";
+
+    // Static --------------------------------------------------------
+
+    /** This is called from the CorrectingSearchCommand.call() method.
+     * Since the first thing done here is to callback the same .call() method
+     * trouble must be taken to avoid the never ending loop by detecting and 
averting the recursive with code like:
+        <code>
+          public SomeSearchCommand extends .. implements 
CorrectingSearchCommand{
+            private volatile boolean inCall = false;
+            ...
+            @Override
+            public ResultList call() {
+
+                try{
+                    inCall = true;
+                    return inCall
+                            ? super.call()
+                            : CorrectingSearchCommandUtility.doCall(this, 
context);
+                }finally{
+                    inCall = false;
+                }
+            }
+            ...
+          }
+        </code>
+     *
+     * @param command
+     * @param cxt
+     * @return
+     */
+    public static ResultList<ResultItem> doCall(final CorrectingSearchCommand 
command, final Context cxt) {
+
+        ResultList<ResultItem> result = command.call();
+
+        // TODO Consider moving the isCorrectionEnabled() call after the
+        // correction has been made and then discarding the result
+        // should the call return false.
+        // Sub classes might not know if the corrected query should be used
+        // until after the query has been run. or at least not after a token
+        // evaluation has been run on the corrected query.
+        if (command.getCorrectionCount() < 
command.getSearchConfiguration().getCorrectingLimit()) {
+
+            // Correct query and parse the resulting query string.
+            final String commandId = cxt.getSearchConfiguration().getId();
+            final String oldQuery = 
cxt.getDataModel().getSearch(commandId).getQuery().getString();
+            final String newQuery = command.correctQuery(result, oldQuery);
+
+            if(!oldQuery.equalsIgnoreCase(newQuery)){
+
+                try {
+
+                    // Create a new command
+                    final CorrectingSearchCommand c = 
command.initialiseNewCommand(createCommand(cxt, command));
+
+                    // and update it to use the corrected query
+                    c.setCorrectedQuery(newQuery);
+
+                    // now execute the command like normal
+                    result = c.call();
+
+//                    // update this command's query to mirror the corrected 
command
+//                    
cxt.getDataModel().getSearch(cxt.getSearchConfiguration().getId())
+//                            
.setQuery(cxt.getDataModel().getSearch(c.getSearchConfiguration().getId()).getQuery());
+
+                    // how many times correction has taken place is useful 
information
+                    result = result.addObjectField(CORRECTION_COUNT, 
c.getCorrectionCount());
+
+                } catch (NoSuchMethodException ex) {
+                    LOG.error(ERR_CANNOT_CREATE_COMMAND, ex);
+                } catch (InstantiationException ex) {
+                    LOG.error(ERR_CANNOT_CREATE_COMMAND, ex);
+                } catch (IllegalAccessException ex) {
+                    LOG.error(ERR_CANNOT_CREATE_COMMAND, ex);
+                } catch (IllegalArgumentException ex) {
+                    LOG.error(ERR_CANNOT_CREATE_COMMAND, ex);
+                } catch (InvocationTargetException ex) {
+                    LOG.error(ERR_CANNOT_CREATE_COMMAND, ex);
+                }
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Corrects the query by looking at the hitCount == 0 and what relevant 
queries are available.
+     *
+     * @param results
+     * @param q
+     * @return
+     */
+    public static String correctQueryFromSpellingSuggestions(
+            final ResultList<ResultItem> results,
+            String q) {
+
+        if(0 == results.getHitCount()){
+
+            final Map<String, List<WeightedSuggestion>> suggestions
+                    = 
((BasicResultList<?>)results).getSpellingSuggestionsMap();
+
+            // Query suggestions is returned in lowercase from Fast, including 
the keys that
+            // maybe had mixed case. Lowers the case first to make the 
replacement work.
+            q = q.toLowerCase();
+
+            for (final List<WeightedSuggestion> suggestionList : 
suggestions.values()) {
+                for (final WeightedSuggestion s : suggestionList) {
+                    q = q.replaceAll(s.getOriginal(), s.getSuggestion());
+                }
+            }
+        }
+
+        return q;
+    }
+
+    // Constructors --------------------------------------------------
+
+    private CorrectingSearchCommandUtility(){}
+
+    // private -------------------------------------------------------
+
+    private static CorrectingSearchCommand createCommand(
+            final SearchCommand.Context cmdCxt,
+            final CorrectingSearchCommand oldCommand)
+            throws NoSuchMethodException, InstantiationException,
+            IllegalAccessException, IllegalArgumentException, 
InvocationTargetException  {
+
+        final Class<? extends CorrectingSearchCommand> clazz = 
oldCommand.getClass();
+        final Constructor<? extends CorrectingSearchCommand> con = 
clazz.getConstructor(Context.class);
+
+        final CorrectingSearchCommand command = con.newInstance(cmdCxt);
+
+        // note the number of times correction has occurred so far
+        command.setCorrectionCount(oldCommand.getCorrectionCount() + 1);
+        return command;
+    }
+
+}


Property changes on: 
branches/2.18/search-command-control-spi/src/main/java/no/sesat/search/mode/command/CorrectingSearchCommandUtility.java
___________________________________________________________________
Added: svn:keywords
   + Id

_______________________________________________
Kernel-commits mailing list
[email protected]
http://sesat.no/mailman/listinfo/kernel-commits

Reply via email to