/* ---- This file is part of SECONDO. Copyright (C) 2012, University Hagen, Faculty of Mathematics and Computer Science, Database Systems for New Applications. SECONDO 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 2 of the License, or (at your option) any later version. SECONDO 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 SECONDO; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ---- //paragraph [10] title: [{\Large \bf ] [}] //characters [1] formula: [$] [$] //[ae] [\"{a}] //[oe] [\"{o}] //[ue] [\"{u}] //[ss] [{\ss}] //[Ae] [\"{A}] //[Oe] [\"{O}] //[Ue] [\"{U}] //[**] [$**$] //[star] [$*$] //[->] [$\rightarrow$] //[toc] [\tableofcontents] //[=>] [\verb+=>+] //[newpage] [\newpage] //[_] [\_] [10] Predicates for Large Query Optimization Algorithm ~Ascending Cost Order (ACO)~ By Gero Willmes, January 2012 Implementations for my master thesis [newpage] [toc] [newpage] */ /* 1 Predicates for Large Query Optimization Algorithm 'Ascending Cost Order (ACO)' */ /* 1.1 aco */ /* ---- aco(+Query, -Stream, -Select2, -Update, -Cost) ---- Description: Main predicate which does the translation of a large predicate set query in ascending cost order (aco). The signature is identical to translate/5. By Gero Willmes Input: ~Query~: Query of Type 'select Args from Rels where Preds' Output: ~Stream~: Plan ~Select2~: Arguments of the select clause ~Update~: Update clause ~Cost~: Cost of the Plan */ aco(Select from Rels where Preds, Stream, Select2, Update, Cost) :- not( optimizerOption(immediatePlan) ), not( optimizerOption(intOrders(_)) ), nl,write('Large Predicate Set Optimization using ascending cost order (aco)!'),nl, %create query graph: qgcreateNodeList(Rels,QGNodeList), retractall(qgEdgeGlobal(_,_,_,_,_,_, _)), createQGEdges(Preds,Rels,QGEdgeList),!, %create spanning tree: kruskal(QGEdgeList,QGNodeList,_,RemovedEdgeList, Plan),!, splitEdges(RemovedEdgeList, RemovedJoinEdges, RemovedSelectionEdges), %integrate selection edges into the plan: embedSelectionEdges(Plan, RemovedSelectionEdges, Plan2),!, %integrate join edges into the plan: embedJoinEdges(Plan2, RemovedJoinEdges, RawPlan),!, Cost is 1.0, Stream = RawPlan, splitSelect(Select, Select2, Update), !, nl. /* 1.2 completesCycle */ /* ---- completesCycle(+A,+B,+SpanTree) ---- Description: Succeeds if the edge (A, B) completes a cycle in the ~SpanTree~ Input: ~A~: Node number ~B~: Node number ~SpanTree~: list of span tree edges */ %selection edges build a cycle in the query graph: completesCycle(A,A,_). %join edges build a cycle if there is already %an existing path from A to B: completesCycle(A,B,SpanTree):- length(SpanTree,L), L > 0, A =\= B, existsPath(A,B,SpanTree). %there is no cycle if the spanning tree is empty %and the node numbers A and B are different: completesCycle(A,B,[]):- A =\= B, !,fail. /* 1.3 completesCycle */ /* ---- completesCycle(+X, +SpanTree) ---- Description: Succeeds if the edge ~X~ completes a cycle in the ~SpanTree~ ~X~ must be of type qgEdge([_], A,B,[_], [_],[_],[_]) Input: ~X~: query graph edge of type qgEdge([_], A,B,[_], [_],[_],[_]) ~SpanTree~: list of span tree edges */ completesCycle(X,SpanTree):- X = qgEdge(_, A,B,_, _,_,_),!, completesCycle(A,B,SpanTree). /* 1.4 kruskal */ /* ---- kruskal(+QEdgeList,+QGNodeList,-SpanTree,-RemovedEdgeList, -Stream) ---- Description: Extended kruskal algorithm Input: ~QGEdgeList~: Edges of a query graph ~QGNodeList~: Nodes of a query graph Output: ~SpanTree~: Edges of the minimum spanning tree calculated from the edges of the query graph ~RemovedEdgeList~: Edges which are member of the query graph but not member of the minimum spanning tree ~Stream~: Plan */ kruskal(QGEdgeList,QGNodeList,SpanTree,RemovedEdgeList, Stream):- retractall(component(nodes(_),_)), createComponents(QGNodeList,_),!, quicksort(QGEdgeList, QGEdgeListSorted),!, kruskal2(QGEdgeListSorted,[], SpanTree,RemovedEdgeList),! %if the query graph was connected %there is a single resulting component: , findall(Plan, component(nodes(_),Plan), ComponentList), length(ComponentList, L), write('kruskal: '), write(L), write('resulting component(s)'),nl, L=1, ComponentList = [Head|_], Stream = Head. /* 1.5 kruskal2 */ /* ---- kruskal2(+QGEdgeList,+AkkSpanTree,-SpanTree,-RemovedEdgeList) ---- Description: kruskal algorithm Input: ~QGEdgeList~: Edges of a query graph ~AkkSpanTree~: Akkumulator for the spanning tree edges Output: ~SpanTree~: Edges of the minimum spanning tree calculated from the edges of the query graph ~RemovedEdgeList~: Edges which are member of the query graph but not member of the minimum spanning tree ~Stream~: Plan */ kruskal2([],Akk, Akk,[]). kruskal2([MaxSpanEdge|EdgeList], AkkSpanTree, SpanTree, RemovedEdgeList):- \+completesCycle(MaxSpanEdge,AkkSpanTree),!, kruskal2(EdgeList,[MaxSpanEdge|AkkSpanTree], SpanTree, RemovedEdgeList),!, reoptimize(MaxSpanEdge). kruskal2([MaxEdge|EdgeList],AkkSpanTree, SpanTree, [MaxEdge|RemovedEdgeList]):- completesCycle(MaxEdge,AkkSpanTree),!, kruskal2(EdgeList,AkkSpanTree, SpanTree, RemovedEdgeList). /* 1.6 createComponents */ /* ---- createComponents(+QGNodeList,-ComponentList) ---- Description: Creates a list of components ~ComponentList~ from a list of query graph nodes ~QGNodeList~. A single component is a structure of type "component(nodes(QGNodeList), Plan)". Initially each component only has a single QGNode in its QGNodeList. Input: ~QGNodeList~: List of query graph nodes Output: ~ComponentList~: List of components */ createComponents([],[]). createComponents([QGNode|QGNodeList], [component(nodes([QGNode]), Plan)|ComponentList]):- QGNode = qgNode(_,rel(X,Y),_), argument(N, rel(X,Y)),!,%neu arg(N) => Plan,%neu %Plan =feed(rel(X,Y)), assert(component(nodes([QGNode]), Plan)), createComponents(QGNodeList, ComponentList). /* 1.7 reoptimize */ /* ---- reoptimize(+SpanEdge) ---- Description: Retrieves the joinable Components and joins them. Two Components are joinable if they contain either the Source Node or the Target Node of the ~SpanEdge~ Input: ~SpanEdge~: Spanning tree edge */ reoptimize(SpanEdge):- joinableComponents(SpanEdge, Component1, Component2),!, joinComponents(SpanEdge, Component1, Component2). /* 1.8 joinComponents */ /* ---- joinComponents(+SpanEdge, +Component1, +Component2) ---- Description: Joins the components ~Component1~ and ~Component2~ to a new Component. Also a new resulting plan is calculated from the old plans of the components and ~SpanEdge~ Input: ~SpanEdge~: Spanning tree edge ~Component1~: Joinable Component ~Component2~: Joinable Component */ joinComponents(SpanEdge, Component1, Component2):- Component1 = component(nodes(NodeList1), Plan1), Component2 = component(nodes(NodeList2), Plan2), append(NodeList1, NodeList2, JoinedNodeList), reoptimizePlan(Plan1, Plan2, SpanEdge, OptimizedPlan), %remove old components and save new component: retract(component(nodes(NodeList1), Plan1)), retract(component(nodes(NodeList2), Plan2)), assert(component(nodes(JoinedNodeList), OptimizedPlan)). /* 1.9 isIncidentEdgeToA */ /* ---- isIncidentEdgeToA(+SpanEdge, -Component) ---- Description: A spanning tree edge is always incident to two components. This predicate determines the first (or left) component to which an edge is incident. Input: ~SpanEdge~: Spanning tree edge Output: ~Component~: First (or left) incident Component */ isIncidentEdgeToA(SpanEdge, Component):- SpanEdge = qgEdge(_, A,_,_, _,_,_), member(qgNode(A,_,_), QGNodes), component(nodes(QGNodes), Plan), Component = component(nodes(QGNodes), Plan). /* 1.10 isIncidentEdgeToB */ /* ---- isIncidentEdgeToB(+SpanEdge, -Component) ---- Description: A spanning tree edge is always incident to two components. This predicate determines the second (or right) component to which an edge is incident. Input: ~SpanEdge~: Spanning tree edge Output: ~Component~: Second (or right) incident Component */ isIncidentEdgeToB(SpanEdge, Component):- SpanEdge = qgEdge(_, _,B,_, _,_,_), member(qgNode(B,_,_), QGNodes), component(nodes(QGNodes), Plan), Component = component(nodes(QGNodes), Plan). /* 1.11 joinableComponents */ /* ---- joinableComponents(+SpanEdge, -Component1, -Component2) ---- Description: A spanning tree edge is always incident to two components. This predicate determines the two components to which an edge is incident. Input: ~SpanEdge~: Spanning tree edge Output: ~Component1~: First (or left) incident Component ~Component2~: Second (or right) incident Component */ joinableComponents(SpanEdge, Component1, Component2):- isIncidentEdgeToA(SpanEdge, Component1), isIncidentEdgeToB(SpanEdge, Component2). /* 1.12 countComponents */ /* ---- countComponents(-N) ---- Description: Counts the number of global facts of type "component(nodes(QGNodes), Plan)" Output: ~N~: Number of global facts of type "component(nodes(QGNodes), Plan)" */ countComponents(N):- findall(component(nodes(QGNodes), Plan), component(nodes(QGNodes), Plan), List),!, length(List, N). %Start predicates to imupdateplancostsplement: /* 1.13 reoptimizePlan */ /* ---- reoptimizePlan(+Plan1, +Plan2, +SpanEdge, -OptimizedPlan) ---- Description: Calculates a new plan ~OptimizedPlan~ from ~Plan1~, ~Plan2~ and ~SpanEdge~ Input: ~Plan1~: First input plan ~Plan2~: Second input plan ~SpanEdge~: Spanning tree edge Output: ~OptimizedPlan~: Resulting plan */ reoptimizePlan(Plan1, Plan2, SpanEdge, OptimizedPlan):- SpanEdge = qgEdge(Pred,_,_,_,_,_,_), assert(componentPlan(1, Plan1)), assert(componentPlan(2, Plan2)), join(res(1), res(2), Pred) => RawPlan, embedComponentPlans(RawPlan, OptimizedPlan), retract(componentPlan(1, Plan1)), retract(componentPlan(2, Plan2)). reoptimizePlan(Plan1, Plan2, SpanEdge, OptimizedPlan):- SpanEdge = qgEdge(Pred,_,_,_,_,_,_), join00(Plan1, Plan2, Pred) => OptimizedPlan. reoptimizePlan(Plan1, Plan2, SpanEdge, OptimizedPlan):- SpanEdge = qgEdge(Pred,_,_,_,_,_,_), %use standard join: OptimizedPlan = symmjoin(Plan1, Plan2, Pred). /* 1.14 splitEdges */ /* ---- splitEdges(+Edges, -JoinEdges, -SelectionEdges) ---- Description: Splits the list of query graph edges ~Edges~ into 2 lists: ~JoinEdges~ and ~SelecitonEdges~ */ splitEdges(Edges, JoinEdges, SelectionEdges):- splitEdges2(Edges, JoinEdges, SelectionEdges). splitEdges2([], [], []). splitEdges2([H|RestEdges],Joins, [H|RestSelections]):- H = qgEdge(_,Source, Source,_,_,_,_), splitEdges2(RestEdges, Joins,RestSelections). splitEdges2([H|RestEdges],[H|RestJoins], Selections):- H = qgEdge(_,Source, Target,_,_,_,_), Source =\= Target, splitEdges2(RestEdges, RestJoins, Selections). /* 1.15 embedComponentPlans */ /* ---- embedComponentPlans(-TermIn, +TermOut) ---- Description: Replaces all terms of typ res(N) in ~TermIn~ by "Term" from the fact componentPlan(N, "Term") and returns the result ~TermOut~ */ embedComponentPlans(res(N), Term) :- componentPlan(N, Term), !. embedComponentPlans(Term, Term2) :- compound(Term), !, Term =.. [Functor | Args], embeddedComponentPlan(Args, Args2), Term2 =.. [Functor | Args2]. embedComponentPlans(Term, Term). embeddedComponentPlan([], []). embeddedComponentPlan([Arg | Args], [Arg2 | Args2]) :- embedComponentPlans(Arg, Arg2), embeddedComponentPlan(Args, Args2). /* 1.16 embedSelectionEdges */ /* ---- embedSelectionEdges(+Plan, +RemovedEdgeList, -ResultPlan) ---- Description: Calculates a new plan ~ResultPlan~ from ~Plan~, and ~RemovedEdgeList~ Input: ~Plan~: Input plan ~RemovedEdgeList~: list of selection edges that were removed from query graph during kruskal algorithm Output: ~ResultPlan~: Resulting plan */ embedSelectionEdges(Plan, [], Plan). embedSelectionEdges(AkkPlan, RemovedEdgeList, ResultPlan):- RemovedEdgeList = [H|Rest], embedSelectionEdge(AkkPlan, NewPlan,H), embedSelectionEdges(NewPlan, Rest, ResultPlan). /* 1.17 embedSelectionEdge */ /* ---- embedSelectionEdge(+PlanFragment, -NewPlanFragment, +Edge) ---- Description: Calculates a new plan fragment ~NewPlanFragment~ from ~PlanFragment~, and ~Edge~ Input: ~PlanFragment~: Input plan fragment ~Edge~: selection edge that was removed from query graph during kruskal algorithm Output: ~NewPlanfragment~: Resulting plan */ embedSelectionEdge(PlanFragment, NewPlanFragment, Edge) :- Edge = qgEdge(Pred, _, _, _,_, _, _), Pred = pr(P, A), argument(N, A), arg(N) => PlanFragment, NewPlanFragment = filter(PlanFragment,P),!. embedSelectionEdge(Term, Term2, Edge) :- compound(Term), !, Term =.. [Functor | Args], embeddedSelectionEdge(Args, Args2, Edge), Term2 =.. [Functor | Args2]. embedSelectionEdge(Term, Term, _). embeddedSelectionEdge([], [],_). embeddedSelectionEdge([Arg | Args], [Arg2 | Args2], Edge) :- embedSelectionEdge(Arg, Arg2, Edge), embeddedSelectionEdge(Args, Args2, Edge). incResultCost(Inc):- resultCost(Old), retractall(resultCost(_)),!, New is Old+Inc, asserta(resultCost(New)). initResultCost:- retractall(resultCost(_)),!, asserta(resultCost(0)). /* 1.18 embedJoinEdge */ /* ---- embedJoinEdge(+Plan, -ResultPlan, +Edge) ---- Description: Replaces an expensive join that is member of the query graph but not member of the spanning tree by a selection edge and embeds it into the ~Plan~ Input: ~Plan~: Input plan ~Edge~: join edge that is member of the query graph but not member of the spanning tree Output: ~ResultPlan~: Resulting plan */ embedJoinEdge(Plan, NewPlan,Edge):- Edge = qgEdge(Pred, _,_,_,_ ,_,_), Pred = pr(P, _, _), NewPlan = filter(Plan,P). /* 1.19 embedJoinEdges */ /* ---- embedJoinEdges(+Plan, +JoinEdges, -ResultPlan) ---- Description: Replaces expensive join edges which are member of the query graph but not member of the spanning tree by selection edges and embeds them into the ~Plan~ Input: ~Plan~: Input plan ~JoinEdges~: join edges which aremember of the query graph but not member of the spanning tree Output: ~ResultPlan~: Resulting plan */ embedJoinEdges(Plan,[] ,Plan). embedJoinEdges(Plan, JoinEdges, NewPlan):- embedJoinEdges2(Plan,JoinEdges, NewPlan). embedJoinEdges2(Resultplan, [], Resultplan). embedJoinEdges2(Plan, [H|Tail], ResultPlan):- embedJoinEdge(Plan, NewPlan, H), embedJoinEdges2(NewPlan, Tail, ResultPlan).