com.o19s.solr.swan.nodes.SwanProxNode.java Source code

Java tutorial

Introduction

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

Source

package com.o19s.solr.swan.nodes;

/**
 * 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.util.ArrayList;
import java.util.List;

import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.spans.SpanQuery;
import org.apache.solr.schema.IndexSchema;

public abstract class SwanProxNode extends SwanNode {

    protected SwanNode _left;
    protected SwanNode _right;
    protected Integer _proximity;

    public SwanProxNode(SwanNode left, SwanNode right, Integer proximity) {
        _left = left;
        _right = right;
        _proximity = proximity;

        if (proximity > 99)
            throw new IllegalArgumentException("For queries; ADJn, NEARn, WITHn, SAMEn. N must not exceed 99.");
    }

    @Override
    public String getField() {
        String field = _field;
        String left = _left.getField();
        String right = _right.getField();

        field = checkSet(field, left);

        field = checkSet(field, right);

        if (field == null)
            return null;

        if (_left instanceof SwanXOrOperationNode) {
            for (SwanNode n : ((SwanOperatorNode) _left).getNodes())
                checkSet(n.getField(), field);
        }

        if (_right instanceof SwanXOrOperationNode) {
            for (SwanNode n : ((SwanOperatorNode) _right).getNodes())
                checkSet(n.getField(), field);
        }

        return field;
    }

    private String checkSet(String set, String check) {
        if (set != null) {
            if (check != null && !check.equals(set))
                throw new IllegalArgumentException("Field mismatch error, Unable to execute query.");
            return set;
        }
        return check;
    }

    @Override
    public Query getQuery(String field) {
        if (_left instanceof SwanOperatorNode || _right instanceof SwanOperatorNode)
            return getConditionalQuery();
        return getSpanQuery(field);
    }

    @Override
    public SpanQuery getSpanQuery(String field) {
        return getSpanQuery(_left, _right, field);
    }

    public abstract SpanQuery getSpanQuery(SwanNode left, SwanNode right, String field);

    @Override
    public boolean isFielded() {
        if (_left.isFielded())
            return true;
        if (_right.isFielded())
            return true;

        return super.isFielded();
    }

    //  protected List<SwanNode> _swanNodes = new ArrayList<SwanNode>();
    //
    //  public void addSwanNode(SwanNode node) {
    //    _swanNodes.add(node);
    //  }

    @Override
    public Query getQuery(String[] fields) {
        if (_left instanceof SwanOperatorNode || _right instanceof SwanOperatorNode)
            return getConditionalQuery();

        return super.getQuery(fields);
    }

    private Query getConditionalQuery() {
        if (_left instanceof SwanXOrOperationNode) {
            if (_right instanceof SwanXOrOperationNode)
                return dualXOrConditionalQuery();
            if (_right instanceof SwanOperatorNode)
                return xOrConditionalQuery(_left, _right, false);
            return singleXOrConditionalQuery(_right, _left, false);
        }
        if (_left instanceof SwanOperatorNode) {
            if (_right instanceof SwanXOrOperationNode)
                return xOrConditionalQuery(_right, _left, true);
            if (_right instanceof SwanOperatorNode)
                return dualConditionalQuery();
            return singleConditionalQuery(_left, _right, false);

        }
        if (_right instanceof SwanXOrOperationNode)
            return singleXOrConditionalQuery(_left, _right, true);
        else
            return singleConditionalQuery(_right, _left, true);
    }

    private Query dualConditionalQuery() {
        String lf_def = _left.getField();
        String rf_def = _right.getField();

        BooleanClause.Occur left_occur = ((SwanOperatorNode) _left).getClause();
        List<SwanNode> left_nodes = ((SwanOperatorNode) _left).getNodes();

        // Logic here for both left and right being an instance of IConditional, lots of ways this can play out.
        BooleanClause.Occur right_occur = ((SwanOperatorNode) _right).getClause();
        List<SwanNode> right_nodes = ((SwanOperatorNode) _right).getNodes();

        if (left_occur.equals(right_occur)) {
            return conditionalQuery(right_occur, left_nodes, right_nodes, lf_def, rf_def);
        } else if (left_occur.equals(BooleanClause.Occur.MUST)) {
            return nestedConditionalQuery(right_occur, left_occur, left_nodes, right_nodes, lf_def, rf_def, false);
        } else {
            return nestedConditionalQuery(left_occur, right_occur, right_nodes, left_nodes, rf_def, lf_def, true);
        }
    }

    private Query nestedConditionalQuery(BooleanClause.Occur innerOccur, BooleanClause.Occur outerOccur,
            List<SwanNode> left, List<SwanNode> right, String lfDef, String rfDef, boolean reverse) {
        BooleanQuery query = new BooleanQuery();
        BooleanQuery innerQuery;
        for (SwanNode l : left) {
            String lf = l.getField() != null ? l.getField() : lfDef;
            innerQuery = new BooleanQuery();
            for (SwanNode r : right) {
                String f = r.getField() != null ? r.getField() : rfDef;
                if (f == null)
                    f = lf;
                else if (lf != null && !lf.equals(f))
                    continue;

                if (reverse)
                    addSpanQuery(innerQuery, innerOccur, r, l, f);
                else
                    addSpanQuery(innerQuery, innerOccur, l, r, f);
            }
            if (innerQuery.getClauses().length == 0)
                throw new IllegalArgumentException("Clauses must have same field.");
            query.add(innerQuery, outerOccur);
        }

        return query;
    }

    private Query conditionalQuery(BooleanClause.Occur occur, List<SwanNode> left, List<SwanNode> right,
            String lfDef, String rfDef) {
        BooleanQuery query = new BooleanQuery();
        for (SwanNode l : left) {
            String lf = l.getField() != null ? l.getField() : lfDef;
            for (SwanNode r : right) {
                String f = r.getField() != null ? r.getField() : rfDef;
                if (f == null)
                    f = lf;
                else if (lf != null && !lf.equals(f))
                    continue;

                addSpanQuery(query, occur, l, r, f);
            }
        }

        return query;
    }

    private Query singleXOrConditionalQuery(SwanNode left, SwanNode right, boolean reverse) {
        BooleanQuery q = (BooleanQuery) singleConditionalQuery(right, left, reverse);
        return xOrNodes(q);
    }

    private Query xOrConditionalQuery(SwanNode left, SwanNode right, boolean reverse) {
        String lf_def = left.getField();
        String rf_def = right.getField();

        BooleanClause.Occur occur = reverse ? ((SwanOperatorNode) right).getClause()
                : ((SwanOperatorNode) left).getClause();
        List<SwanNode> left_nodes = ((SwanOperatorNode) left).getNodes();
        List<SwanNode> right_nodes = ((SwanOperatorNode) right).getNodes();

        List<Query> nodes = new ArrayList<Query>();

        for (SwanNode left_node : left_nodes) {
            BooleanQuery outer = new BooleanQuery();
            String lf = checkSet(left_node.getField(), lf_def);

            for (SwanNode right_node : right_nodes) {
                String rf = checkSet(right_node.getField(), rf_def);
                String f = checkSet(lf, rf);

                if (reverse)
                    addSpanQuery(outer, occur, right_node, left_node, f);
                else
                    addSpanQuery(outer, occur, left_node, right_node, f);
            }
            nodes.add(outer);
        }

        return xOrNodes(nodes);
    }

    private Query dualXOrConditionalQuery() {
        String lf_def = _left.getField();
        String rf_def = _right.getField();

        List<Query> nodes = new ArrayList<Query>();

        for (SwanNode left : ((SwanOperatorNode) _left).getNodes()) {
            String lf = checkSet(left.getField(), lf_def);
            for (SwanNode right : ((SwanOperatorNode) _right).getNodes()) {
                String rf = checkSet(right.getField(), rf_def);
                String f = checkSet(lf, rf);

                // TODO: This I believe can be refactored to something cleaner.
                if (f == null) {
                    BooleanQuery inner = new BooleanQuery();
                    for (String _f : defaultFields)
                        inner.add(getSpanQuery(left, right, _f), BooleanClause.Occur.SHOULD);
                    nodes.add(inner);
                } else {
                    nodes.add(getSpanQuery(left, right, f));
                }
            }
        }

        return xOrNodes(nodes);
    }

    private Query xOrNodes(BooleanQuery query) {
        List<Query> queries = new ArrayList<Query>(query.getClauses().length);
        for (BooleanClause clause : query.getClauses())
            queries.add(clause.getQuery());
        return xOrNodes(queries);
    }

    private Query xOrNodes(List<Query> queries) {
        BooleanQuery query = new BooleanQuery();
        ArrayList<Query> sub_nodes = new ArrayList<Query>(queries.size());

        for (int x = 0; x < queries.size(); x++) {
            sub_nodes.clear();
            sub_nodes.addAll(queries);
            sub_nodes.remove(x);

            BooleanQuery inner = new BooleanQuery();
            for (Query q : sub_nodes)
                inner.add(q, BooleanClause.Occur.MUST_NOT);
            inner.add(queries.get(x), BooleanClause.Occur.MUST);
            query.add(inner, BooleanClause.Occur.SHOULD);
        }

        return query;
    }

    private Query singleConditionalQuery(SwanNode left, SwanNode right, boolean reverse) {
        BooleanQuery query = new BooleanQuery();
        String lf_def = left.getField();
        String rf_def = right.getField();

        BooleanClause.Occur outerOccur = left instanceof SwanXOrOperationNode ? BooleanClause.Occur.MUST
                : ((SwanOperatorNode) left).getClause();
        List<SwanNode> left_nodes = ((SwanOperatorNode) left).getNodes();

        for (SwanNode l : left_nodes) {
            String lf = l.getField() != null ? l.getField() : lf_def;
            if (lf != null && rf_def != null && !lf.equals(rf_def))
                throw new IllegalArgumentException("Clauses must have same field.");
            if (lf == null)
                lf = rf_def;

            if (reverse)
                addSpanQuery(query, outerOccur, right, l, lf);
            else
                addSpanQuery(query, outerOccur, l, right, lf);
        }

        return query;
    }

    private void addSpanQuery(BooleanQuery query, BooleanClause.Occur occur, SwanNode left, SwanNode right,
            String field) {
        if (field == null) {
            if (occur.equals(BooleanClause.Occur.SHOULD))
                // Optimize OR queries, don't require nesting
                for (String _f : defaultFields)
                    query.add(getSpanQuery(left, right, _f), BooleanClause.Occur.SHOULD);
            else {
                BooleanQuery q = new BooleanQuery();
                for (String _f : defaultFields)
                    q.add(getSpanQuery(left, right, _f), BooleanClause.Occur.SHOULD);
                query.add(q, occur);
            }
        } else
            query.add(getSpanQuery(left, right, field), occur);
    }

    @Override
    public void setSchema(IndexSchema schema) {
        _left.setSchema(schema);
        _right.setSchema(schema);
        super.setSchema(schema);
    }
}