xref: /plugin/sphinxsearch-was/SphinxSearch.php (revision 124:e4ba7c830a72)
1<?php
2/*
3 * To change this template, choose Tools | Templates
4 * and open the template in the editor.
5 */
6
7class SphinxSearch
8{
9    private $_sphinx = null;
10    private $_result = array();
11    private $_index = null;
12    private $_query = '';
13
14    private $_snippetSize = 256;
15    private $_aroundKeyword = 5;
16    private $_resultsPerPage = 10;
17
18    private $_titlePriority = 1;
19    private $_bodyPriority = 1;
20    private $_namespacePriority = 1;
21    private $_pagenamePriority = 1;
22
23    public function  __construct($host, $port, $index)
24    {
25        $this->_sphinx = new SphinxClient();
26        $this->_sphinx->SetServer($host, $port);
27        $this->_sphinx->SetMatchMode(SPH_MATCH_EXTENDED2);
28
29        $this->_index = $index;
30    }
31
32    public function setSearchAllQuery($keywords, $categories)
33    {
34        $keywords = $this->_sphinx->EscapeString($keywords);
35        $keywords = $this->_enableQuotesAndDefis($keywords);
36        $starKeyword = $this->starQuery($keywords);
37        $this->_query = "(@(namespace,pagename) $starKeyword) | (@(body,title) {$keywords})";
38    }
39
40    public function setSearchAllQueryWithCategoryFilter($keywords, $categories)
41    {
42        $keywords = $this->_sphinx->EscapeString($keywords);
43        $keywords = $this->_enableQuotesAndDefis($keywords);
44        $starKeyword = $this->starQuery($keywords);
45        if(strpos($categories, "-") === 0){
46            $categories = '-"'.substr($categories, 1).'"';
47        }
48        $this->_query = "(@(namespace,pagename) {$categories}) & ((@(body,title) {$keywords}) | (@(namespace,pagename) {$starKeyword}))";
49    }
50
51    public function setSearchCategoryQuery($keywords, $categories)
52    {
53        $keywords = $this->_sphinx->EscapeString($keywords);
54        $keywords = $this->_enableQuotesAndDefis($keywords);
55
56        $starKeyword = $this->starQuery($keywords);
57        if (!empty($categories)){
58            $this->_query = "(@(namespace,pagename) $categories $starKeyword)";
59        } else {
60            $this->_query = "(@(namespace,pagename) $starKeyword)";
61        }
62
63    }
64
65    public function setSearchOnlyPagename()
66    {
67    	$this->_query = "(@(pagename) {$this->_query})";
68    }
69
70    public function search($start, $resultsPerPage = 10)
71    {
72        $this->_resultsPerPage = $resultsPerPage;
73
74        $this->_sphinx->SetFieldWeights(array(
75            'namespace' => $this->_namespacePriority,
76            'pagename' => $this->_pagenamePriority,
77            'title' => $this->_titlePriority,
78            'body' => $this->_bodyPriority)
79        );
80
81        $this->_sphinx->SetLimits($start, $resultsPerPage+100);
82
83        $res = $this->_sphinx->Query($this->_query, $this->_index);
84
85        $this->_result = $res;
86
87        if (empty($res['matches'])) {
88            return false;
89	}
90        return true;
91    }
92
93    public function getPages($keywords)
94    {
95        if (empty($this->_result['matches'])) {
96            return false;
97	}
98
99        $pagesIdsAll = $this->getPagesIds();
100        $this->_offset = 0;
101        $counter = 0;
102        $tmpRes = array();
103        $pagesIds = array();
104        foreach($pagesIdsAll as $id => $pageData){
105            $this->_offset++;
106            if(auth_quickaclcheck($pageData['page']) >= AUTH_READ){
107                if(!isset($tmpRes[$pageData['page']])){
108                    $tmpRes[$pageData['page']] = 1;
109                    $counter++;
110                }
111                $pagesIds[$id] = $pageData;
112                if ($counter == $this->_resultsPerPage){
113                    break;
114                }
115            }
116        }
117        if (empty($pagesIds)){
118            return false;
119        }
120
121        $pagesList = array();
122        $body = array();
123        $titleText = array();
124        $category = array();
125        foreach ($pagesIds as $crc => $data){
126            if (empty($data['page'])){
127                continue;
128            }
129            if (!empty($data['hid'])){
130                $bodyHtml = p_render('xhtml',p_get_instructions(getSectionByTitleLevel($data['page'], $data['title'], true)),$info);
131            } else {
132                $bodyHtml = p_wiki_xhtml($data['page']);
133            }
134            $bodyHtml = preg_replace("#[\s]+?</li>#", "</li>;", $bodyHtml);
135            $bodyHtml = htmlspecialchars_decode($bodyHtml);
136            $body[$crc] = strip_tags($bodyHtml);
137            if(!empty($data['title_text'])){
138                $titleText[$crc] = strip_tags($data['title_text']);
139            } else {
140                $titleText[$crc] = $data['page'];
141            }
142            $category[$crc] = $data['page'];
143        }
144
145        //$starQuery = $this->starQuery($keywords);
146        $bodyExcerpt = $this->getExcerpt($body, $keywords);
147        $titleTextExcerpt = $this->getExcerpt($titleText, $keywords);
148        $i = 0;
149        $results = array();
150        foreach($body as $crc => $notused){
151            $results[$crc] = array(
152                'page' => $pagesIds[$crc]['page'],
153                'bodyExcerpt' => $bodyExcerpt[$i],
154                'titleTextExcerpt' => $titleTextExcerpt[$i],
155                'hid' => $pagesIds[$crc]['hid'],
156                'title' => $pagesIds[$crc]['title'],
157                'title_text' => $pagesIds[$crc]['title_text']
158            );
159            $i++;
160        }
161        return $results;
162    }
163
164    public function getPagesIds()
165    {
166        $pageMapper = new PageMapper();
167
168        return $pageMapper->getByCrc(array_keys($this->_result['matches']));
169    }
170
171    public function getOffset()
172    {
173        return $this->_offset;
174    }
175
176    public function getError()
177    {
178        return $this->_sphinx->GetLastError();
179    }
180
181    public function getTotalFound()
182    {
183        return !empty($this->_result['total_found'])?$this->_result['total_found'] : 0;
184    }
185
186    public function getExcerpt($data, $query)
187    {
188        return $this->_sphinx->BuildExcerpts($data, $this->_index, $query,
189                    array(
190                        'limit' => $this->_snippetSize,
191                        'around' => $this->_aroundKeyword,
192                        'weight_order' => 1,
193                        'sp' => 1
194                    )
195                );
196    }
197
198    public function starQuery($query)
199    {
200        $query = $this->removeStars($query);
201        $words = explode(" ", $query);
202        foreach($words as $id => $word){
203            $words[$id] = "*".$word."*";
204        }
205        return implode(" ", $words);
206    }
207
208    public function removeStars($query)
209    {
210        $words = explode(" ", $query);
211        foreach($words as $id => $word){
212            $words[$id] = trim($word, "*");
213        }
214        return implode(" ", $words);
215    }
216
217    public function getQuery()
218    {
219        return $this->_query;
220    }
221
222    public function setSnippetSize($symbols = 256)
223    {
224        $this->_snippetSize = $symbols;
225    }
226
227    public function setArroundWordsCount($words = 5)
228    {
229        $this->_aroundKeyword = $words;
230    }
231
232    public function setTitlePriority($priority)
233    {
234        $this->_titlePriority = $priority;
235    }
236
237    public function setBodyPriority($priority)
238    {
239        $this->_bodyPriority = $priority;
240    }
241
242    public function setNamespacePriority($priority)
243    {
244        $this->_namespacePriority = $priority;
245    }
246
247    public function setPagenamePriority($priority)
248    {
249        $this->_pagenamePriority = $priority;
250    }
251
252    private function _enableQuotesAndDefis($query)
253    {
254        $query = ' '. $query;
255        $quotesCount = count(explode('"', $query))-1;
256        if ($quotesCount && $quotesCount%2 == 0){
257            $query = str_replace('\"', '"', $query);
258        }
259        $query = preg_replace("#\s\\\-(\w)#ui", " -$1", $query);
260
261        $query = substr($query, 1);
262
263        return $query;
264    }
265}
266