com.o19s.solr.swan.LuceneSwanSearcher.java Source code

Java tutorial

Introduction

Here is the source code for com.o19s.solr.swan.LuceneSwanSearcher.java

Source

package com.o19s.solr.swan;

/**
 * Copyright 2012 OpenSource Connections, 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.lang.reflect.InvocationTargetException;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.solr.common.params.SolrParams;

import com.google.common.collect.ListMultimap;
import com.o19s.solr.swan.nodes.SwanAdjNode;
import com.o19s.solr.swan.nodes.SwanAndOperationNode;
import com.o19s.solr.swan.nodes.SwanNearNode;
import com.o19s.solr.swan.nodes.SwanNode;
import com.o19s.solr.swan.nodes.SwanNotNode;
import com.o19s.solr.swan.nodes.SwanOperatorNode;
import com.o19s.solr.swan.nodes.SwanOrOperationNode;
import com.o19s.solr.swan.nodes.SwanPhraseNode;
import com.o19s.solr.swan.nodes.SwanRangeNode;
import com.o19s.solr.swan.nodes.SwanSameNode;
import com.o19s.solr.swan.nodes.SwanTermNode;
import com.o19s.solr.swan.nodes.SwanWithNode;
import com.o19s.solr.swan.nodes.SwanXOrOperationNode;

public class LuceneSwanSearcher implements ISwanSearcher<SwanNode> {

    private static String defaultOp = "adj";
    private static String stemSuffix = "_stem";
    private ListMultimap<String, String> _fieldAliases;

    public LuceneSwanSearcher(SolrParams params, ListMultimap<String, String> fieldAliases) {
        _fieldAliases = fieldAliases;
        SwanNode.setParams(params);
        String defOpStr = params.get("q.op");
        if (defOpStr != null) {
            defaultOp = defOpStr.toLowerCase();
        }
    }

    @Override
    public SwanNode or(SwanNode left, SwanNode right) {
        // This clause says if left is an OR condition, add right as an additional
        // OR in the same scope.
        // example if left = (X OR Y), and right = (Z), we will return (X OR Y OR Z)
        // If left or right have different fields, they should fall out of this and 
        // result in (X OR Y) OR (Z) so the different fields can be used
        if (left instanceof SwanOrOperationNode
                && nodesAreUnfieldedOrHaveSameFields(left.getField(), right.getField())) {
            ((SwanOrOperationNode) left).add(right);
            return left;
        }
        return new SwanOrOperationNode(left, right);
    }

    @Override
    public SwanNode xor(SwanNode left, SwanNode right) {
        if (left instanceof SwanXOrOperationNode && !left.isWrapped()) {
            ((SwanXOrOperationNode) left).add(right);
            return left;
        }
        return new SwanXOrOperationNode(left, right);
    }

    @Override
    public SwanNode and(SwanNode left, SwanNode right) {
        if (left instanceof SwanAndOperationNode) {
            ((SwanAndOperationNode) left).add(right);
            return left;
        }
        return new SwanAndOperationNode(left, right);
    }

    @Override
    public SwanNode same(SwanNode left, SwanNode right, int n) {
        return new SwanSameNode(left, right, n);
    }

    @Override
    public SwanNode with(SwanNode left, SwanNode right, int n) {
        return new SwanWithNode(left, right, n);
    }

    @Override
    public SwanNode near(SwanNode left, SwanNode right, int n) {
        return new SwanNearNode(left, right, n);
    }

    @Override
    public SwanNode adj(SwanNode left, SwanNode right, int n) {
        return new SwanAdjNode(left, right, n);
    }

    @Override
    public SwanNode defaultOp(SwanNode left, SwanNode right) {
        Class[] unamenableToSwan = new Class[] { SwanRangeNode.class };
        boolean swanSafe = true;
        for (Class c : unamenableToSwan) {
            if ((c == left.getClass()) || (c == right.getClass())) {
                swanSafe = false;
                break;
            }
        }
        // TODO: Figure out what this is for
        //      System.out.println("In LSS.dO, "+ left.getClass() +" --- "+ right.getClass() );
        if (defaultOp.equals("same") && swanSafe) {
            return same(left, right, 1);
        } else if (defaultOp.equals("with") && swanSafe) {
            return with(left, right, 1);
        } else if (defaultOp.equals("adj") && swanSafe) {
            return adj(left, right, 1);
        } else if (defaultOp.equals("near") && swanSafe) {
            return near(left, right, 1);
        } else if (defaultOp.equals("and") || !swanSafe) { //<-- defaults to AND if not swanSafe
            return and(left, right);
        } else if (defaultOp.equals("or")) {
            return or(left, right);
        } else {
            throw new UnsupportedOperationException(
                    "Default operator may only be on of SAME, WITH, ADJ, NEAR, AND, OR. Was suplied with "
                            + defaultOp);
        }
    }

    @Override
    public SwanNode not(SwanNode left, SwanNode right) {
        return new SwanNotNode(left, right);
    }

    @Override
    public SwanNode term(String match) {
        return new SwanTermNode(match);
    }

    @Override
    public SwanNode phrase(String match) {
        return new SwanPhraseNode(match);
    }

    @Override
    public SwanNode range(String field, String op1, String val1) {
        if (_fieldAliases.containsKey(field.toLowerCase())) {
            return new SwanRangeNode(_fieldAliases.get(field.toLowerCase()).get(0), op1, val1);
        }
        return new SwanRangeNode(field, op1, val1);
    }

    @Override
    public SwanNode classRange(String field, String mainClassification, String subClassification1,
            String subClassification2) {
        return new SwanRangeNode(field, ">=", mainClassification + "/" + subClassification1, "<=",
                mainClassification + "/" + subClassification2);
    }

    @Override
    public SwanNode boundRange(String field, String op1, String val1, String op2, String val2) {
        if (_fieldAliases.containsKey(field.toLowerCase())) {
            return new SwanRangeNode(_fieldAliases.get(field.toLowerCase()).get(0), op1, val1, op2, val2);
        }
        return new SwanRangeNode(field, op1, val1, op2, val2);
    }

    @Override
    public SwanNode fieldedSubExpressions(String field, SwanNode expression) {
        if (expression instanceof SwanOperatorNode) {
            for (SwanNode node : ((SwanOperatorNode) expression).getNodes()) {
                fieldedSubExpressions(field, node);
            }
        } else {
            fieldedExpression(field, expression);
        }
        return expression;
    }

    @Override
    public SwanNode fieldedExpression(String field, SwanNode expression) {
        field = field.toLowerCase();
        if (SwanNode.isFieldStemming()) {
            field = field.concat(stemSuffix);
        }

        if (_fieldAliases.containsKey(field)) {
            try {
                return getFieldAliasExpression(_fieldAliases.get(field), expression);
            } catch (Exception ex) {
                //need to do something here.  Log? pass the exception on?
            }
        }
        expression.setField(field);
        return expression;
    }

    private SwanNode getFieldAliasExpression(List<String> fields, SwanNode originalExpression)
            throws IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException,
            InvocationTargetException, NoSuchMethodException {
        if (fields.size() == 1) {
            originalExpression.setField(fields.get(0));
            return originalExpression;
        }
        //set up 'or' conditions between all of the fields if there are more than one
        SwanNode aggregatedExpression = null;
        for (String field : fields) {
            if (field != null) {
                //use copy constructor to make a copy of the original expression
                SwanNode newExpression = originalExpression.getClass().getConstructor(originalExpression.getClass())
                        .newInstance(originalExpression);
                newExpression.setField(field);
                if (aggregatedExpression != null) {
                    aggregatedExpression = or(aggregatedExpression, newExpression);
                } else {
                    aggregatedExpression = newExpression;
                }
            }
        }
        return aggregatedExpression;
    }

    private boolean nodesAreUnfieldedOrHaveSameFields(String firstField, String secondField) {
        return ((StringUtils.isBlank(firstField) || StringUtils.isBlank(secondField))
                || (StringUtils.equals(firstField, secondField)));
    }

    @Override
    public SwanNode wrap(SwanNode peek) {
        peek.setWrapped();
        return peek;
    }
}