PageRenderTime 23ms CodeModel.GetById 11ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/biblio_list_sphinx.inc.php

https://github.com/masir/ucs-2.0
PHP | 328 lines | 224 code | 24 blank | 80 comment | 45 complexity | 95024abd54446122251f77663b11d2e8 MD5 | raw file
  1. <?php
  2. /**
  3. * biblio_list class
  4. * Class for generating list of bibliographic records from SPHINX index
  5. *
  6. * Copyright (C) 2010 Arie Nugraha (dicarve@yahoo.com)
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. *
  22. */
  23. // be sure that this file not accessed directly
  24. if (!defined('INDEX_AUTH')) {
  25. die("can not access this file directly");
  26. } elseif (INDEX_AUTH != 1) {
  27. die("can not access this file directly");
  28. }
  29. class biblio_list extends biblio_list_model
  30. {
  31. protected $options = array('host' => '127.0.0.1', 'port' => 9312, 'index' => 'slims',
  32. 'mode' => null, 'timeout' => 0, 'filter' => '@last_update desc',
  33. 'filtervals' => array(), 'groupby' => null, 'groupsort' => null,
  34. 'sortby' => null, 'sortexpr' => null, 'distinct' => 'biblio_id',
  35. 'select' => null, 'limit' => 20, 'max_limit' => 500000,
  36. 'ranker' => null);
  37. protected $offset = 0;
  38. private $sphinx = null;
  39. private $sphinx_error = false;
  40. private $no_query = false;
  41. private $sphinx_no_result = false;
  42. /**
  43. * Class Constructor
  44. *
  45. * @param object $obj_db
  46. * @param integer $int_num_show
  47. */
  48. public function __construct($obj_db, $int_num_show)
  49. {
  50. parent::__construct($obj_db, $int_num_show);
  51. if (!class_exists('SphinxClient')) {
  52. throw new Exception('SPHINX API Library is not installed yet!');
  53. } else {
  54. $this->sphinx = new SphinxClient();
  55. // check searchd status
  56. $_sphinx_status = $this->sphinx->Status();
  57. if (!$_sphinx_status) {
  58. throw new Exception('SPHINX Server is not running! Please
  59. check if it already configured correctly.');
  60. }
  61. // defaults
  62. $this->options['mode'] = SPH_MATCH_EXTENDED2;
  63. $this->options['ranker'] = SPH_RANK_PROXIMITY_BM25;
  64. // get page number from http get var
  65. if (!isset($_GET['page']) OR $_GET['page'] < 1){ $_page = 1; } else {
  66. $_page = (integer)$_GET['page'];
  67. }
  68. $this->current_page = $_page;
  69. // count the row offset
  70. if ($this->current_page <= 1) { $_offset = 0; } else {
  71. $this->offset = ($this->current_page*$this->num2show) - $this->num2show;
  72. }
  73. }
  74. }
  75. /**
  76. * Compile SQL
  77. *
  78. * @return string
  79. */
  80. public function compileSQL()
  81. {
  82. $_sql_str = 'SELECT SQL_CALC_FOUND_ROWS index.biblio_id, index.title,
  83. index.author, index.image, index.isbn_issn, index.labels
  84. FROM search_biblio AS `index`';
  85. if (isset($this->criteria['sql_criteria'])) {
  86. $_sql_str .= ' WHERE '.$this->criteria['sql_criteria'];
  87. } else if ($this->sphinx_no_result) {
  88. $_sql_str .= " WHERE index.biblio_id<0";
  89. } else {
  90. $this->no_query = true;
  91. $_sql_str .= " WHERE index.biblio_id IS NOT NULL";
  92. }
  93. // ordering
  94. $_sql_str .= ' ORDER BY index.last_update DESC ';
  95. // set limit when query is empty
  96. if (!isset($this->criteria['sql_criteria']) || $this->no_query) {
  97. $_sql_str .= ' LIMIT '.$this->offset.','.$this->num2show;
  98. }
  99. return $_sql_str;
  100. }
  101. /**
  102. * Method to print out document records
  103. *
  104. * @param object $obj_db
  105. * @param integer $int_num2show
  106. * @param boolean $bool_return_output
  107. * @return string
  108. */
  109. public function getDocumentList($bool_return_output = true)
  110. {
  111. global $sysconf;
  112. if ($this->sphinx_error) {
  113. $this->resultset = false;
  114. } else {
  115. $_sql_str = $this->compileSQL();
  116. if ($this->no_query) {
  117. // start time
  118. $_start = function_exists('microtime')?microtime(true):time();
  119. // execute query
  120. $this->resultset = $this->obj_db->query($_sql_str);
  121. if ($this->obj_db->error) {
  122. $this->query_error = $this->obj_db->error;
  123. }
  124. // get total number of rows from query
  125. $_total_q = $this->obj_db->query('SELECT FOUND_ROWS()');
  126. $_total_d = $_total_q->fetch_row();
  127. $this->num_rows = $_total_d[0];
  128. // end time
  129. $_end = function_exists('microtime')?microtime(true):time();
  130. $this->query_time = round($_end-$_start, 5);
  131. } else {
  132. $this->resultset = $this->obj_db->query($_sql_str);
  133. }
  134. if ($this->obj_db->error) {
  135. $this->query_error = $this->obj_db->error;
  136. }
  137. }
  138. if ($bool_return_output) {
  139. // return the html result
  140. return $this->makeOutput();
  141. }
  142. }
  143. /**
  144. * Set sphinx search option
  145. *
  146. * @param array $arr_options
  147. * @return void
  148. */
  149. public function setOptions($arr_options)
  150. {
  151. $this->options = $arr_options;
  152. }
  153. /**
  154. * Method to set search criteria
  155. *
  156. * @param string $str_criteria
  157. * @return void
  158. */
  159. public function setSQLcriteria($str_criteria)
  160. {
  161. if (!$str_criteria)
  162. return null;
  163. // defaults
  164. $_query_str = '';
  165. $_searched_fields = array();
  166. $_previous_field = '';
  167. $_boolean = '';
  168. // parse query
  169. $this->orig_query = $str_criteria;
  170. $_queries = simbio_tokenizeCQL($str_criteria, $this->searchable_fields, $this->stop_words, $this->queries_word_num_allowed);
  171. // var_dump($_queries);
  172. if (count($_queries) < 1) {
  173. return null;
  174. }
  175. // loop each query
  176. // echo '<pre>'; var_dump($_queries); echo '</pre>';
  177. foreach ($_queries as $_num => $_query) {
  178. // field
  179. $_field = $_query['f'];
  180. // break the loop if we meet `cql_end` field
  181. if ($_field == 'cql_end') { break; }
  182. // if field is boolean
  183. if ($_field == 'boolean') {
  184. if ($_query['b'] == '*') { $_query_str .= ' | '; } else { $_query_str .= ' & '; }
  185. continue;
  186. } else {
  187. if ($_query['b'] == '*') { $_b = ''; } else { $_b = $_query['b']; }
  188. $_q = @$this->obj_db->escape_string($_query['q']);
  189. $_q = isset($_query['is_phrase'])?'"'.$_q.'"':$_q;
  190. $_boolean = '';
  191. }
  192. // for debugging purpose only
  193. // echo "<p>$_num. $_field -> $_boolean -> $_query_str</p><p>&nbsp;</p>";
  194. // check fields
  195. switch ($_field) {
  196. case 'author' :
  197. $_q = $_b.$_q;
  198. $_query_str .= " @author $_q";
  199. break;
  200. case 'subject' :
  201. $_q = $_b.$_q;
  202. $_query_str .= " @topic $_q";
  203. break;
  204. case 'location' :
  205. $_q = $_b.$_q;
  206. $_query_str .= " @location $_q";
  207. break;
  208. case 'colltype' :
  209. $_q = $_b.$_q;
  210. $_query_str .= " @collection_types $_q";
  211. break;
  212. case 'itemcode' :
  213. $_q = $_b.$_q;
  214. $_query_str .= " @items $_q";
  215. break;
  216. case 'callnumber' :
  217. $_q = $_b.$_q;
  218. $_query_str .= " @call_number $_q";
  219. break;
  220. case 'itemcallnumber' :
  221. $_q = $_b.$_q;
  222. $_query_str .= " @item_call_number $_q";
  223. break;
  224. case 'class' :
  225. $_q = $_b.$_q;
  226. $_query_str .= " @classification $_q";
  227. break;
  228. case 'isbn' :
  229. $_q = $_b.$_q;
  230. $_query_str .= " @isbn_issn $_q";
  231. break;
  232. case 'publisher' :
  233. $_q = $_b.$_q;
  234. $_query_str .= " @publisher $_q";
  235. break;
  236. case 'publishyear' :
  237. $_q = $_b.$_q;
  238. $_query_str .= " @publish_year $_q";
  239. break;
  240. case 'gmd' :
  241. $_q = $_b.$_q;
  242. $_query_str .= " @gmd $_q";
  243. break;
  244. case 'notes' :
  245. $_q = $_b.$_q;
  246. $_query_str .= " @notes $_q";
  247. break;
  248. default :
  249. $_q = $_b.$_q;
  250. $_query_str .= " @(title,series) $_q";
  251. break;
  252. }
  253. }
  254. // check if query is empty
  255. if (!$_query_str) {
  256. $this->no_query = true;
  257. $_sql_criteria = 'index.biblio_id IS NOT NULL';
  258. $this->criteria = array('sql_criteria' => $_sql_criteria, 'searched_fields' => $_searched_fields);
  259. return $this->criteria;
  260. }
  261. // set options
  262. $this->sphinx->SetServer ( $this->options['host'], $this->options['port'] );
  263. $this->sphinx->SetConnectTimeout ( $this->options['timeout'] );
  264. $this->sphinx->SetArrayResult ( true );
  265. $this->sphinx->SetWeights ( array ( 100, 1 ) );
  266. $this->sphinx->SetMatchMode ( $this->options['mode'] );
  267. if (count($this->options['filtervals'])) { $this->sphinx->SetFilter ( $this->options['filter'], $this->options['filtervals'] ); }
  268. if ($this->options['groupby']) { $this->sphinx->SetGroupBy ( $this->options['groupby'], SPH_GROUPBY_ATTR, $this->options['groupsort'] ); }
  269. if ($this->options['sortby']) {
  270. $this->sphinx->SetSortMode ( SPH_SORT_EXTENDED, $this->options['sortby'] );
  271. $this->sphinx->SetSortMode ( SPH_SORT_EXPR, $this->options['sortexpr'] );
  272. }
  273. $this->sphinx->SetGroupDistinct ( $this->options['distinct'] );
  274. if ($this->options['select']) { $this->sphinx->SetSelect ( $this->options['select'] ); }
  275. $this->sphinx->SetLimits ( $this->offset, $this->num2show?$this->num2show:$this->options['limit'], $this->options['max_limit'] );
  276. $this->sphinx->SetRankingMode ( $this->options['ranker'] );
  277. // invoke sphinx query
  278. $_search_result = $this->sphinx->Query($_query_str, $this->options['index']);
  279. // echo '<pre>'; var_dump($_search_result); echo '</pre>'; die();
  280. if ($_search_result === false) {
  281. $this->sphinx_error = true;
  282. $this->query_error = $this->sphinx->GetLastError();
  283. return false;
  284. }
  285. if (isset($_search_result['matches']) && is_array($_search_result['matches'])) {
  286. $_matched_ids = '(';
  287. foreach ($_search_result['matches'] as $_match) {
  288. $_matched_ids .= $_match['id'].',';
  289. }
  290. // remove last comma
  291. $_matched_ids = substr_replace($_matched_ids, '', -1);
  292. $_matched_ids .= ')';
  293. $_sql_criteria = "index.biblio_id IN $_matched_ids";
  294. $this->num_rows = $_search_result['total_found'];
  295. $this->query_time = $_search_result['time'];
  296. $this->criteria = array('sql_criteria' => $_sql_criteria, 'searched_fields' => $_searched_fields);
  297. return $this->criteria;
  298. } else {
  299. $this->sphinx_no_result = true;
  300. return false;
  301. }
  302. }
  303. }
  304. ?>