source: Dev/branches/rest-dojo-ui/Demo/rdfapi/sparql/SparqlEngineDb/QuerySimplifier.php @ 312

Last change on this file since 312 was 312, checked in by jkraaijeveld, 13 years ago
File size: 4.9 KB
Line 
1<?php
2
3/**
4*   Simplifies ("flattens") Query objects that have graph
5*   patterns which are subpatterns of other patterns.
6*
7*   Example:
8*      ?g ?h ?i .
9*      {
10*        {?person <some://typ/e> 'asd'}
11*        UNION
12*        {?person3 <some://typ/es2> 'three'}
13*      }
14*    is represented internally as three graph patterns, the latter
15*    two referencing the first to be their pattern (they are subpatternOf).
16*    Now this can be flattened to this which is the same:
17*      {?g ?h ?i . ?person <some://typ/e> 'asd'}
18*      UNION
19*      {?g ?h ?i .?person3 <some://typ/es2> 'three'}
20*
21*   This class does this.
22*
23*   @author Christian Weiske <cweiske@cweiske.de>
24*   @license http://www.gnu.org/licenses/lgpl.html LGPL
25*/
26class SparqlEngineDb_QuerySimplifier
27{
28
29    /**
30    *   Simplify the query by flattening out subqueries.
31    *   Modifies the passed query object directly.
32    */
33    public function simplify(Query $query)
34    {
35        $arPatterns = $query->getResultPart();
36        self::dropEmpty($arPatterns);
37        $arPlan     = $this->createPlan($arPatterns);
38        if (count($arPlan) == 0) {
39            $query->setResultPart($arPatterns);
40            return 0;
41        }
42
43        $this->executePlan($arPatterns, $arPlan);
44        $query->setResultPart($arPatterns);
45    }//public function simplify(Query $query)
46
47
48
49    /**
50    *   Creates a plan what to do.
51    *
52    *   @return array Array of arrays. Key is the parent pattern id,
53    *               value is an array of subpatterns that belong to
54    *               that parental pattern.
55    */
56    protected function createPlan(&$arPatterns)
57    {
58        $arNumbers = $this->getNumbers($arPatterns);
59        if (count($arNumbers) == 0) {
60            return array();
61        }
62
63        $arPlan    = array();
64
65        foreach ($arNumbers as $nId => $nPatternCount) {
66            $nParent = $arPatterns[$nId]->getSubpatternOf();
67            $arPlan[$nParent][$nId] = true;
68        }
69
70        return $arPlan;
71    }//protected function createPlan(&$arPatterns)
72
73
74
75    /**
76    *   Executes the plan
77    *
78    *   @param array $arPatterns  Array of GraphPatterns
79    *   @param array $arPlan      Plan array as returned by createPlan()
80    */
81    protected function executePlan(&$arPatterns, &$arPlan)
82    {
83        foreach ($arPlan as $nParent => $arChildren) {
84            $base        = $arPatterns[$nParent];
85            $grandParent = $base->getSubpatternOf();
86            $nNextId     = $nParent;
87            foreach ($arChildren as $nChild => $null) {
88                $new = clone $base;
89                $new->addTriplePatterns($arPatterns[$nChild]->getTriplePatterns());
90                $new->addConstraints(   $arPatterns[$nChild]->getConstraints());
91                $new->setId($nNextId);
92                if ($nParent != $nNextId) {
93                    $new->setUnion($nParent);
94                }
95                $arPatterns[$nNextId] = $new;
96
97                if ($grandParent !== null) {
98                    //dynamically adjust plan
99                    $arPlan[$grandParent][$nNextId] = true;
100                }
101
102                $nNextId = $nChild;
103            }
104            //last one is not not needed anymore
105            unset($arPatterns[$nNextId]);
106        }
107    }//protected function executePlan(&$arPatterns, &$arPlan)
108
109
110
111    /**
112    *   Returns an array of id-value pairs determining
113    *   which pattern IDs (array id) are deepest nested
114    *   (higher value).
115    *   Array is sorted in reverse order, highest values
116    *   first.
117    *
118    *   @param array $arPatterns    Array with GraphPatterns
119    *   @return array Array with key-value pairs
120    */
121    protected function getNumbers(&$arPatterns)
122    {
123        $arNumbers = array();
124        foreach ($arPatterns as $nId => &$pattern) {
125            $nParent = $pattern->getSubpatternOf();
126            if ($nParent !== null) {
127                $arNumbers[$nId] = $arNumbers[$nParent] + 1;
128            } else {
129                $arNumbers[$nId] = 0;
130            }
131        }
132        //remove the not so interesting ones
133        foreach ($arNumbers as $nId => $nNumber) {
134            if ($nNumber == 0) {
135                unset($arNumbers[$nId]);
136            }
137        }
138
139        arsort($arNumbers);
140
141        return $arNumbers;
142    }//protected function getNumbers(&$arPatterns)
143
144
145
146    /**
147    *   Removes all empty graph patterns from the array.
148    *   Modifies it directly.
149    */
150    protected static function dropEmpty(&$arPatterns)
151    {
152        foreach ($arPatterns as $nId => &$pattern) {
153            if ($pattern->isEmpty()) {
154                unset($arPatterns[$nId]);
155            }
156        }
157
158        foreach ($arPatterns as $nId => &$pattern) {
159            $nParent = $pattern->getSubpatternOf();
160            if (!isset($arPatterns[$nParent])) {
161                $arPatterns[$nId]->setSubpatternOf(null);
162            }
163        }
164        //FIXME: continued indexes?
165    }//protected static function dropEmpty(&$arPatterns)
166
167}//class SparqlEngineDb_QuerySimplifier
168
169?>
Note: See TracBrowser for help on using the repository browser.