sphinxsearch.php 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. <?php
  2. /*
  3. * StatusNet - the distributed open-source microblogging tool
  4. * Copyright (C) 2008, 2009, StatusNet, Inc.
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. if (!defined('STATUSNET')) {
  20. exit(1);
  21. }
  22. class SphinxSearch extends SearchEngine
  23. {
  24. private $sphinx;
  25. private $connected;
  26. function __construct($target, $table)
  27. {
  28. $fp = @fsockopen(common_config('sphinx', 'server'), common_config('sphinx', 'port'));
  29. if (!$fp) {
  30. $this->connected = false;
  31. return;
  32. }
  33. fclose($fp);
  34. parent::__construct($target, $table);
  35. $this->sphinx = new SphinxClient;
  36. $this->sphinx->setServer(common_config('sphinx', 'server'), common_config('sphinx', 'port'));
  37. $this->connected = true;
  38. }
  39. function is_connected()
  40. {
  41. return $this->connected;
  42. }
  43. function limit($offset, $count, $rss = false)
  44. {
  45. //FIXME without LARGEST_POSSIBLE, the most recent results aren't returned
  46. // this probably has a large impact on performance
  47. $LARGEST_POSSIBLE = 1e6;
  48. if ($rss) {
  49. $this->sphinx->setLimits($offset, $count, $count, $LARGEST_POSSIBLE);
  50. }
  51. else {
  52. // return at most 50 pages of results
  53. $this->sphinx->setLimits($offset, $count, 50 * ($count - 1), $LARGEST_POSSIBLE);
  54. }
  55. return $this->target->limit(0, $count);
  56. }
  57. function query($q)
  58. {
  59. $result = $this->sphinx->query($q, $this->remote_table());
  60. if ($result === false) {
  61. throw new ServerException($this->sphinx->getLastError());
  62. }
  63. if (!isset($result['matches'])) return false;
  64. $id_set = join(', ', array_keys($result['matches']));
  65. $this->target->whereAdd("id in ($id_set)");
  66. return true;
  67. }
  68. function set_sort_mode($mode)
  69. {
  70. switch ($mode) {
  71. case 'chron':
  72. $this->sphinx->SetSortMode(SPH_SORT_ATTR_DESC, 'created_ts');
  73. return $this->target->orderBy('id desc');
  74. break;
  75. case 'reverse_chron':
  76. $this->sphinx->SetSortMode(SPH_SORT_ATTR_ASC, 'created_ts');
  77. return $this->target->orderBy('id asc');
  78. break;
  79. case 'nickname_desc':
  80. if ($this->table != 'profile') {
  81. throw new Exception(
  82. 'nickname_desc sort mode can only be use when searching profile.'
  83. );
  84. } else {
  85. $this->sphinx->SetSortMode(SPH_SORT_ATTR_DESC, 'nickname');
  86. return $this->target->orderBy('id desc');
  87. }
  88. break;
  89. case 'nickname_asc':
  90. if ($this->table != 'profile') {
  91. throw new Exception(
  92. 'nickname_desc sort mode can only be use when searching profile.'
  93. );
  94. } else {
  95. $this->sphinx->SetSortMode(SPH_SORT_ATTR_ASC, 'nickname');
  96. return $this->target->orderBy('id asc');
  97. }
  98. break;
  99. default:
  100. $this->sphinx->SetSortMode(SPH_SORT_ATTR_DESC, 'created_ts');
  101. return $this->target->orderBy('id desc');
  102. break;
  103. }
  104. }
  105. function remote_table()
  106. {
  107. return $this->dbname() . '_' . $this->table;
  108. }
  109. function dbname()
  110. {
  111. // @fixme there should be a less dreadful way to do this.
  112. // DB objects won't give database back until they connect, it's confusing
  113. if (preg_match('!^.*?://.*?:.*?@.*?/(.*?)$!', common_config('db', 'database'), $matches)) {
  114. return $matches[1];
  115. }
  116. // TRANS: Server exception thrown when a database name cannot be identified.
  117. throw new ServerException(_m("Sphinx search could not identify database name."));
  118. }
  119. }