PageRenderTime 58ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/biblio_list_sphinx.inc.php

https://gitlab.com/mucill/majalengka
PHP | 329 lines | 223 code | 26 blank | 80 comment | 54 complexity | 6f6bda0ddec57a87b2c412019d040d56 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 3 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. parent::__construct($obj_db, $int_num_show);
  50. if (!class_exists('SphinxClient')) {
  51. throw new Exception('SPHINX API Library is not installed yet!');
  52. } else {
  53. $this->sphinx = new SphinxClient();
  54. // check searchd status
  55. $_sphinx_status = $this->sphinx->Status();
  56. if (!$_sphinx_status) {
  57. throw new Exception('SPHINX Server is not running! Please
  58. check if it already configured correctly.');
  59. }
  60. // defaults
  61. $this->options['mode'] = SPH_MATCH_EXTENDED2;
  62. $this->options['ranker'] = SPH_RANK_PROXIMITY_BM25;
  63. // get page number from http get var
  64. if (!isset($_GET['page']) OR $_GET['page'] < 1){ $_page = 1; } else {
  65. $_page = (integer)$_GET['page'];
  66. }
  67. $this->current_page = $_page;
  68. // count the row offset
  69. if ($this->current_page <= 1) { $_offset = 0; } else {
  70. $this->offset = ($this->current_page*$this->num2show) - $this->num2show;
  71. }
  72. }
  73. }
  74. /**
  75. * Compile SQL
  76. *
  77. * @return string
  78. */
  79. public function compileSQL()
  80. {
  81. $_sql_str = 'SELECT SQL_CALC_FOUND_ROWS index.biblio_id, index.title,
  82. index.author, index.image, index.isbn_issn, index.labels
  83. FROM search_biblio AS `index`';
  84. if (isset($this->criteria['sql_criteria'])) {
  85. $_sql_str .= ' WHERE '.$this->criteria['sql_criteria'];
  86. } else if ($this->sphinx_no_result) {
  87. $_sql_str .= " WHERE index.biblio_id<0";
  88. } else {
  89. $this->no_query = true;
  90. $_sql_str .= " WHERE index.biblio_id IS NOT NULL";
  91. }
  92. // ordering
  93. $_sql_str .= ' ORDER BY index.last_update DESC ';
  94. // set limit when query is empty
  95. if (!isset($this->criteria['sql_criteria']) || $this->no_query) {
  96. $_sql_str .= ' LIMIT '.$this->offset.','.$this->num2show;
  97. }
  98. return $_sql_str;
  99. }
  100. /**
  101. * Method to print out document records
  102. *
  103. * @param object $obj_db
  104. * @param integer $int_num2show
  105. * @param boolean $bool_return_output
  106. * @return string
  107. */
  108. public function getDocumentList($bool_return_output = true) {
  109. global $sysconf;
  110. if ($this->sphinx_error) {
  111. $this->resultset = false;
  112. } else {
  113. $_sql_str = $this->compileSQL();
  114. if ($this->no_query) {
  115. // start time
  116. $_start = function_exists('microtime')?microtime(true):time();
  117. // execute query
  118. $this->resultset = $this->obj_db->query($_sql_str);
  119. if ($this->obj_db->error) {
  120. $this->query_error = $this->obj_db->error;
  121. }
  122. // get total number of rows from query
  123. $_total_q = $this->obj_db->query('SELECT FOUND_ROWS()');
  124. $_total_d = $_total_q->fetch_row();
  125. $this->num_rows = $_total_d[0];
  126. // end time
  127. $_end = function_exists('microtime')?microtime(true):time();
  128. $this->query_time = round($_end-$_start, 5);
  129. } else {
  130. $this->resultset = $this->obj_db->query($_sql_str);
  131. }
  132. if ($this->obj_db->error) {
  133. $this->query_error = $this->obj_db->error;
  134. }
  135. }
  136. if ($bool_return_output) {
  137. // return the html result
  138. return $this->makeOutput();
  139. }
  140. }
  141. /**
  142. * Set sphinx search option
  143. *
  144. * @param array $arr_options
  145. * @return void
  146. */
  147. public function setOptions($arr_options) {
  148. $this->options = $arr_options;
  149. }
  150. /**
  151. * Method to set search criteria
  152. *
  153. * @param string $str_criteria
  154. * @return void
  155. */
  156. public function setSQLcriteria($str_criteria) {
  157. if (!$str_criteria) return null;
  158. // defaults
  159. $_query_str = '';
  160. $_searched_fields = array();
  161. $_previous_field = '';
  162. $_boolean = '';
  163. $_b = '';
  164. // parse query
  165. $this->orig_query = $str_criteria;
  166. $_queries = simbio_tokenizeCQL($str_criteria, $this->searchable_fields, $this->stop_words, $this->queries_word_num_allowed);
  167. // var_dump($_queries);
  168. if (count($_queries) < 1) { return null; }
  169. // loop each query
  170. // echo '<pre>'; var_dump($_queries); echo '</pre>';
  171. foreach ($_queries as $_num => $_query) {
  172. // field
  173. $_field = $_query['f'];
  174. if ($_previous_field <> $_field) {
  175. if ($_field != 'boolean') {
  176. $_query_str .= '';
  177. } else {
  178. $_query_str .= ')';
  179. }
  180. }
  181. // break the loop if we meet `cql_end` field
  182. if ($_field == 'cql_end') { continue; }
  183. // if field is boolean
  184. if ($_field == 'boolean') {
  185. if ($_query['b'] == '*') { $_query_str .= ' | '; } else { $_query_str .= ' & '; }
  186. continue;
  187. } else {
  188. if ($_query['b'] == '-') {
  189. $_query_str .= ' -';
  190. } else if ($_query['b'] == '*') {
  191. $_query_str .= ' | ';
  192. } else {
  193. $_query_str .= ' ';
  194. }
  195. $_q = @$this->obj_db->escape_string($_query['q']);
  196. $_q = isset($_query['is_phrase'])?'"'.$_q.'"':$_q;
  197. $_boolean = '';
  198. }
  199. if ($_previous_field == $_field) {
  200. $_query_str .= $_q;
  201. continue;
  202. }
  203. $_previous_field = $_field;
  204. // for debugging purpose only
  205. // echo "<p>$_num. $_field -> $_boolean -> $_query_str</p><p>&nbsp;</p>";
  206. // check fields
  207. $_q = $_b.$_q;
  208. switch ($_field) {
  209. case 'author' :
  210. $_query_str .= " (@author $_q";
  211. break;
  212. case 'subject' :
  213. $_query_str .= " (@topic $_q";
  214. break;
  215. case 'location' :
  216. $_query_str .= " (@location $_q";
  217. break;
  218. case 'colltype' :
  219. $_query_str .= " (@collection_types $_q";
  220. break;
  221. case 'itemcode' :
  222. $_query_str .= " (@items $_q";
  223. break;
  224. case 'callnumber' :
  225. $_query_str .= " (@call_number $_q";
  226. break;
  227. case 'itemcallnumber' :
  228. $_query_str .= " (@item_call_number $_q";
  229. break;
  230. case 'class' :
  231. $_query_str .= " (@classification $_q";
  232. break;
  233. case 'isbn' :
  234. $_query_str .= " (@isbn_issn $_q";
  235. break;
  236. case 'publisher' :
  237. $_query_str .= " (@publisher $_q";
  238. break;
  239. case 'publishyear' :
  240. $_query_str .= " (@publish_year $_q";
  241. break;
  242. case 'gmd' :
  243. $_query_str .= " (@gmd $_q";
  244. break;
  245. case 'notes' :
  246. $_query_str .= " (@notes $_q";
  247. break;
  248. default :
  249. $_query_str .= " (@title $_q";
  250. break;
  251. }
  252. }
  253. $_query_str .= ')';
  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. }