Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
Copyright 2013 Red Hat, Inc. and/or its affiliates.
This file is part of lightblue.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
package com.redhat.lightblue.assoc.ep;
import java.util.List;
import java.util.ArrayList;
import java.util.Set;
import java.util.HashSet;
import java.util.Collection;
import java.util.Map;
import java.util.HashMap;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.redhat.lightblue.query.QueryExpression;
import com.redhat.lightblue.query.Projection;
import com.redhat.lightblue.query.FieldProjection;
import com.redhat.lightblue.query.ProjectionList;
import com.redhat.lightblue.query.Sort;
import com.redhat.lightblue.metadata.CompositeMetadata;
import com.redhat.lightblue.metadata.ResolvedReferenceField;
import com.redhat.lightblue.metadata.ObjectField;
import com.redhat.lightblue.metadata.ArrayField;
import com.redhat.lightblue.metadata.ArrayElement;
import com.redhat.lightblue.metadata.ObjectArrayElement;
import com.redhat.lightblue.metadata.SimpleArrayElement;
import com.redhat.lightblue.metadata.ReferenceField;
import com.redhat.lightblue.metadata.FieldTreeNode;
import com.redhat.lightblue.metadata.FieldCursor;
import com.redhat.lightblue.assoc.QueryPlan;
import com.redhat.lightblue.assoc.QueryPlanNode;
import com.redhat.lightblue.assoc.Conjunct;
import com.redhat.lightblue.assoc.QueryPlanData;
import com.redhat.lightblue.assoc.QueryFieldInfo;
import com.redhat.lightblue.crud.CRUDOperationContext;
import com.redhat.lightblue.eval.SortFieldInfo;
import com.redhat.lightblue.util.Path;
/**
* Execution plan is a tree of execution blocks. Every node in the query plan is
* converted to an execution block, and connected in the same way query plan
* nodes are connected. Each execution block contains a pipeline, and every step
* of the pipeline performs a step of the operation.
*
* The search plan and retrieval plan are constructed differently.
*
* In the retrieval plan, the root entity is at the root, and every destination
* node is a child node. So, the assembler first runs the parent node, gets the
* docs, and then runs the child nodes and attaches the documents to the slots.
*
* Query plan is optional, and it has a different layout than the retrieval
* plan. All that we do with the query plan is to retrieve the root node
* documents, so query plan does not retrieve all associated entities.
*/
public class ExecutionPlan {
static private final Logger LOGGER = LoggerFactory.getLogger(ExecutionPlan.class);
private Step resultStep;
/**
* Creates an execution plan
*
* @param requestQuery query requested by the client
* @param requestProjection projection requested by the client
* @param requestSort sort requested by the client.
* @param from request.from
* @param to request.to
* @param rootMd Root entity composite metadata
* @param searchQueryPlan if the results of a search is to be retrieved in a
* second pass, not null. Otherwise, null.
* @param retrievalQueryPlan Never null. Contains the plan for the retrieval
* of found documents. If the searchQueryPlan is not null, retrieves the
* documents found by that search. If searchQueryPlan is null, this plan
* performs the search and retrieval.
*/
public ExecutionPlan(QueryExpression requestQuery,
Projection requestProjection,
Sort requestSort,
Long from,
Long to,
CompositeMetadata rootMd,
QueryPlan searchQueryPlan,
QueryPlan retrievalQueryPlan,
CRUDOperationContext ctx) {
// Specifies if a filtering layer is needed at the end of the
// pipeline. This is needed if searchplan returns more than
// what's necessary (e.g. if there are query clauses that are
// not assigned to query plan nodes or edges)
boolean needsFinalFiltering=false;
// This is set to true when we identify the step that sets matchcount
boolean matchCountSet=false;
// This is set if there are queries associated with the nodes
// that are not the root node of the retrieval plan
boolean queries_in_non_root_nodes=false;
for(QueryPlanNode node:retrievalQueryPlan.getAllNodes()) {
if(node.getSources().length!=0&& // non-root
!node.getData().getConjuncts().isEmpty()) {
queries_in_non_root_nodes=true;
break;
}
}
// First, create execution blocks for every node in the search and
// retrieval plans. We keep a map of query plan nodes to execution
// blocks to keep query plan immutable.
// This needs to be done in two steps: first we create the
// nodes, then we attach them to each other.
ExecutionBlock rootEntityInQueryPlan = null;
Map qp2BlockMap = new HashMap<>();
if (searchQueryPlan != null) {
// Create nodes
for (QueryPlanNode node : searchQueryPlan.getAllNodes()) {
ExecutionBlock block = new ExecutionBlock(rootMd, node);
if (node.getMetadata().getParent() == null) {
rootEntityInQueryPlan = block;
}
qp2BlockMap.put(node, block);
}
}
ExecutionBlock retrievalRoot = null;
for (QueryPlanNode node : retrievalQueryPlan.getAllNodes()) {
ExecutionBlock block = new ExecutionBlock(rootMd, node);
if (node.getMetadata().getParent() == null) {
retrievalRoot = block;
}
qp2BlockMap.put(node, block);
}
// Connect the blocks
for (Map.Entry entry : qp2BlockMap.entrySet()) {
for (QueryPlanNode source : entry.getKey().getSources()) {
entry.getValue().addSourceBlock(qp2BlockMap.get(source));
}
}
List qfi=null;
if (searchQueryPlan != null) {
LOGGER.debug("Building execution plan from search query plan:{}", searchQueryPlan);
List unassigned = searchQueryPlan.getUnassignedClauses();
// If query root has destinations in the search query plan, then
// those destinations are inaccessible, becase we evaluate the search plan
// up to root. That means, we'll need to filter
if(!unassigned.isEmpty()||rootEntityInQueryPlan.getQueryPlanNode().getDestinations().length>0)
needsFinalFiltering=true;
qfi = getAllQueryFieldInfo(searchQueryPlan);
// Lets see if the root entity is the only source of this plan
QueryPlanNode[] qpSources = searchQueryPlan.getSources();
boolean rootIsTheOnlySource = qpSources.length == 1 && qpSources[0].getMetadata().getParent() == null;
for (QueryPlanNode node : searchQueryPlan.getAllNodes()) {
ExecutionBlock block = qp2BlockMap.get(node);
AbstractSearchStep search;
if (block.getSourceBlocks().isEmpty()) {
search = new Search(block);
block.setResultStep(search);
} else {
for (ExecutionBlock source : block.getSourceBlocks()) {
QueryPlanData edgeData = searchQueryPlan.getEdgeData(source.getQueryPlanNode(),
block.getQueryPlanNode());
if (edgeData != null) {
AssociationQuery aq = new AssociationQuery(rootMd,
block.getMetadata(),
block.getReference(),
edgeData.getConjuncts());
block.setAssociationQuery(source, aq);
}
}
// Block has sources. Join them
List