Package org.sindice.siren.qparser.keyword.processors

Source Code of org.sindice.siren.qparser.keyword.processors.GroupQueryNodeProcessor

/**
* Copyright 2014 National University of Ireland, Galway.
*
* This file is part of the SIREn project. Project and contact information:
*
*  https://github.com/rdelbru/SIREn
*
* 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.
*/
package org.sindice.siren.qparser.keyword.processors;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.lucene.queryparser.flexible.core.QueryNodeException;
import org.apache.lucene.queryparser.flexible.core.config.QueryConfigHandler;
import org.apache.lucene.queryparser.flexible.core.nodes.AndQueryNode;
import org.apache.lucene.queryparser.flexible.core.nodes.BooleanQueryNode;
import org.apache.lucene.queryparser.flexible.core.nodes.GroupQueryNode;
import org.apache.lucene.queryparser.flexible.core.nodes.ModifierQueryNode;
import org.apache.lucene.queryparser.flexible.core.nodes.ModifierQueryNode.Modifier;
import org.apache.lucene.queryparser.flexible.core.nodes.OrQueryNode;
import org.apache.lucene.queryparser.flexible.core.nodes.QueryNode;
import org.apache.lucene.queryparser.flexible.core.parser.SyntaxParser;
import org.apache.lucene.queryparser.flexible.core.processors.QueryNodeProcessor;
import org.apache.lucene.queryparser.flexible.standard.config.StandardQueryConfigHandler.ConfigurationKeys;
import org.apache.lucene.queryparser.flexible.standard.config.StandardQueryConfigHandler.Operator;
import org.apache.lucene.queryparser.flexible.standard.nodes.BooleanModifierNode;
import org.sindice.siren.qparser.keyword.nodes.ArrayQueryNode;
import org.sindice.siren.qparser.keyword.nodes.DatatypeQueryNode;
import org.sindice.siren.qparser.keyword.nodes.TopLevelQueryNode;
import org.sindice.siren.qparser.keyword.nodes.TwigQueryNode;
import org.sindice.siren.qparser.keyword.nodes.WildcardNodeQueryNode;

/**
* The {@link SyntaxParser} generates query node trees that consider the boolean
* operator precedence, but Lucene current syntax does not support boolean
* precedence, so this processor remove all the precedence and apply the
* equivalent modifier according to the boolean operation defined on an specific
* query node.
*
* <p>
*
* The original {@link org.apache.lucene.queryparser.flexible.standard.processors.GroupQueryNodeProcessor}
* was not supporting correctly nested groups. This processor interprets a
* {@link GroupQueryNode} and merges it with the node above it.
*/
public class GroupQueryNodeProcessor implements QueryNodeProcessor {

  private ArrayList<QueryNode> queryNodeList;

  private boolean latestNodeVerified;

  private QueryConfigHandler queryConfig;

  private Boolean usingAnd = false;

  public GroupQueryNodeProcessor() {
    // empty constructor
  }

  public QueryNode process(QueryNode queryTree) throws QueryNodeException {
    if (!this.getQueryConfigHandler().has(ConfigurationKeys.DEFAULT_OPERATOR)) {
      throw new IllegalArgumentException(
          "DEFAULT_OPERATOR should be set on the QueryConfigHandler");
    }

    this.usingAnd = Operator.AND == this.getQueryConfigHandler()
    .get(ConfigurationKeys.DEFAULT_OPERATOR) ? true : false;

    if (queryTree instanceof GroupQueryNode) {
      queryTree = ((GroupQueryNode) queryTree).getChild();
    }

    this.queryNodeList = new ArrayList<QueryNode>();
    this.latestNodeVerified = false;
    this.readTree(queryTree);

    if (queryTree instanceof BooleanQueryNode) {
      queryTree.set(this.queryNodeList);
      return queryTree;
    }
    else {
      return new BooleanQueryNode(this.queryNodeList);
    }

  }

  /**
   */
  private QueryNode applyModifier(final QueryNode node, final QueryNode parent) {

    if (this.usingAnd) {

      if (parent instanceof OrQueryNode) {

        if (node instanceof ModifierQueryNode) {

          final ModifierQueryNode modNode = (ModifierQueryNode) node;

          if (modNode.getModifier() == Modifier.MOD_REQ) {
            return modNode.getChild();
          }

        }
      } else {

        if (node instanceof ModifierQueryNode) {

          final ModifierQueryNode modNode = (ModifierQueryNode) node;

          if (modNode.getModifier() == Modifier.MOD_NONE) {
            return new BooleanModifierNode(modNode.getChild(), Modifier.MOD_REQ);
          }

        } else {
          return new BooleanModifierNode(node, Modifier.MOD_REQ);
        }

      }

    } else {

      if (parent instanceof AndQueryNode) {

        if (node instanceof ModifierQueryNode) {

          final ModifierQueryNode modNode = (ModifierQueryNode) node;

          if (modNode.getModifier() == Modifier.MOD_NONE) {
            return new BooleanModifierNode(modNode.getChild(), Modifier.MOD_REQ);
          }

        } else {
          return new BooleanModifierNode(node, Modifier.MOD_REQ);
        }

      }
    }

    return node;
  }

  private void readTree(final QueryNode node) throws QueryNodeException {

    if (node instanceof BooleanQueryNode) {
      final List<QueryNode> children = node.getChildren();

      if (children != null && children.size() > 0) {

        for (int i = 0; i < children.size() - 1; i++) {
          this.readTree(children.get(i));
        }

        this.processNode(node);
        this.readTree(children.get(children.size() - 1));

      } else {
        this.processNode(node);
      }

    } else {
      this.processNode(node);
    }

  }

  private void processNode(final QueryNode node) throws QueryNodeException {
    if (node instanceof AndQueryNode || node instanceof OrQueryNode) {
      if (!this.latestNodeVerified && !this.queryNodeList.isEmpty()) {
        this.queryNodeList.add(this.applyModifier(this.queryNodeList
            .remove(this.queryNodeList.size() - 1), node));
        this.latestNodeVerified = true;
      }
    }
    else if (node instanceof GroupQueryNode) {
      final ArrayList<QueryNode> actualQueryNodeList = this.queryNodeList;
      actualQueryNodeList.add(this.applyModifier(this.process(node), node.getParent()));
      this.queryNodeList = actualQueryNodeList;
      this.latestNodeVerified = false;
    }
    else if (node instanceof TwigQueryNode) {
      final ArrayList<QueryNode> actualQueryNodeList = this.queryNodeList;
      final TwigQueryNode twigNode = (TwigQueryNode) node;
      final QueryNode root = twigNode.getRoot();
      final QueryNode child = twigNode.getChild();
      if (!(root instanceof WildcardNodeQueryNode)) { // the root is not empty
        twigNode.setRoot(this.process(root));
      }
      if (!(child instanceof WildcardNodeQueryNode)) { // the child is not empty
        twigNode.setChild(this.process(child));
      }
      actualQueryNodeList.add(twigNode);
      this.queryNodeList = actualQueryNodeList;
      this.latestNodeVerified = false;
    }
    else if (node instanceof ArrayQueryNode) {
      final ArrayList<QueryNode> actualQueryNodeList = this.queryNodeList;
      final ArrayQueryNode arrayNode = (ArrayQueryNode) node;
      final List<QueryNode> children = arrayNode.getChildren();
      final List<QueryNode> newChildren = new ArrayList<QueryNode>();
      for (final QueryNode child : children) {
        // The unary modifier sets the occurrence of this value in the TwigQuery
        if (!(child instanceof ModifierQueryNode)) {
          newChildren.add(this.process(child));
        } else {
          newChildren.add(child);
        }
      }
      arrayNode.set(newChildren);
      actualQueryNodeList.add(arrayNode);
      this.queryNodeList = actualQueryNodeList;
      this.latestNodeVerified = false;
    }
    else if (node instanceof TopLevelQueryNode) {
      final ArrayList<QueryNode> actualQueryNodeList = this.queryNodeList;
      final TopLevelQueryNode topNode = (TopLevelQueryNode) node;
      final QueryNode child = topNode.getChildren().get(0);
      topNode.set(Arrays.asList(this.process(child)));
      actualQueryNodeList.add(topNode);
      this.queryNodeList = actualQueryNodeList;
      this.latestNodeVerified = false;
    }
    else if (node instanceof DatatypeQueryNode) {
      final ArrayList<QueryNode> actualQueryNodeList = this.queryNodeList;
      final DatatypeQueryNode dtNode = (DatatypeQueryNode) node;
      final QueryNode child = dtNode.getChild();
      dtNode.set(Arrays.asList(this.applyModifier(this.process(child), node.getParent())));
      actualQueryNodeList.add(dtNode);
      this.queryNodeList = actualQueryNodeList;
      this.latestNodeVerified = false;
    }
    else if (!(node instanceof BooleanQueryNode)) {
      this.queryNodeList.add(this.applyModifier(node, node.getParent()));
      this.latestNodeVerified = false;
    }
  }

  public QueryConfigHandler getQueryConfigHandler() {
    return this.queryConfig;
  }

  public void setQueryConfigHandler(final QueryConfigHandler queryConfigHandler) {
    this.queryConfig = queryConfigHandler;
  }

}
TOP

Related Classes of org.sindice.siren.qparser.keyword.processors.GroupQueryNodeProcessor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.