mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-28 17:01:16 +00:00
Make sphinx only supported search engine
This commit is contained in:
@@ -92,7 +92,7 @@ class NntmuxResetDb extends Command
|
||||
DB::commit();
|
||||
$this->info('Truncating completed.');
|
||||
|
||||
(new SphinxSearch())->truncateRTIndex('releases_rt');
|
||||
(new SphinxSearch())->truncateRTIndex();
|
||||
|
||||
$this->info('Deleting nzbfiles subfolders.');
|
||||
$files = File::allfiles(Settings::settingValue('..nzbpath'));
|
||||
|
||||
@@ -126,6 +126,7 @@
|
||||
"doctrine/dbal": "^2.6",
|
||||
"exeu/apai-io": "~2.0",
|
||||
"fideloper/proxy": "~4.0",
|
||||
"foolz/sphinxql-query-builder": "^1.2",
|
||||
"fxp/composer-asset-plugin": "~1.1",
|
||||
"google/recaptcha": "~1.1",
|
||||
"guzzlehttp/guzzle": "^6.3",
|
||||
|
||||
Generated
+52
-1
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "1806a48bc325099c9d406fbca3d061bf",
|
||||
"content-hash": "992dad8589b7bcfa04eab6f13dc1256a",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adrenth/thetvdb2",
|
||||
@@ -2356,6 +2356,57 @@
|
||||
],
|
||||
"time": "2018-02-07T20:20:57+00:00"
|
||||
},
|
||||
{
|
||||
"name": "foolz/sphinxql-query-builder",
|
||||
"version": "1.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/FoolCode/SphinxQL-Query-Builder.git",
|
||||
"reference": "ca6e6836b5f1bc5077e0d179874aa252440ea4dc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/FoolCode/SphinxQL-Query-Builder/zipball/ca6e6836b5f1bc5077e0d179874aa252440ea4dc",
|
||||
"reference": "ca6e6836b5f1bc5077e0d179874aa252440ea4dc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"replace": {
|
||||
"foolz/sphinxql": "self.version"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "6.3.*"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Foolz\\SphinxQL\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"Apache-2.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "foolz",
|
||||
"email": "support@foolz.us"
|
||||
}
|
||||
],
|
||||
"description": "A PHP query builder for SphinxQL. Uses MySQLi to connect to the Sphinx server.",
|
||||
"homepage": "http://www.foolz.us",
|
||||
"keywords": [
|
||||
"database",
|
||||
"query builder",
|
||||
"search",
|
||||
"sphinx",
|
||||
"sphinxql",
|
||||
"sql"
|
||||
],
|
||||
"time": "2017-11-07T14:00:57+00:00"
|
||||
},
|
||||
{
|
||||
"name": "fxp/composer-asset-plugin",
|
||||
"version": "v1.4.2",
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
return [
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 9306,
|
||||
'index' => 'releases_rt'
|
||||
];
|
||||
@@ -1,21 +1,16 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
require_once dirname(__DIR__, 2).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use nntmux\db\DB;
|
||||
use nntmux\ReleaseSearch;
|
||||
|
||||
if (NN_RELEASE_SEARCH_TYPE != ReleaseSearch::SPHINX) {
|
||||
exit('Error, NN_RELEASE_SEARCH_TYPE in nntmux/config/settings.php must be set to SPHINX!'.PHP_EOL);
|
||||
}
|
||||
|
||||
$sphinxConnection = '';
|
||||
if ($argc == 3 && is_numeric($argv[2])) {
|
||||
if ($argc === 3 && is_numeric($argv[2])) {
|
||||
$sphinxConnection = sprintf('sphinx://%s:%d/', $argv[1], $argv[2]);
|
||||
} elseif ($argc == 2) {
|
||||
} elseif ($argc === 2) {
|
||||
// Checks that argv[1] exists AND that there are no other arguments, which would be an error.
|
||||
$socket = preg_replace('#^(?:unix://)?(.*)$#', '$1', $argv[1]);
|
||||
if (substr($socket, 0, 1) == '/') {
|
||||
if ($socket[0] === '/') {
|
||||
// Make sure the socket path is fully qualified (and using correct separator).
|
||||
$sphinxConnection = sprintf('unix://%s:', $socket);
|
||||
}
|
||||
@@ -43,8 +38,10 @@ $tables = [];
|
||||
$tables['releases_se'] = sprintf($tableSQL_releases, $sphinxConnection);
|
||||
|
||||
foreach ($tables as $table => $query) {
|
||||
$pdo->queryExec(sprintf('DROP TABLE IF EXISTS %s', $table));
|
||||
$pdo->queryExec($query);
|
||||
DB::unprepared("DROP TABLE IF EXISTS $table;");
|
||||
DB::commit();
|
||||
DB::unprepared($query);
|
||||
DB::commit();
|
||||
}
|
||||
|
||||
echo 'All done! If you messed up your sphinx connection info, you can rerun this script.'.PHP_EOL;
|
||||
|
||||
@@ -4,7 +4,4 @@ require_once dirname(__DIR__, 2).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use nntmux\SphinxSearch;
|
||||
|
||||
if (! isset($argv[1]) || ! in_array($argv[1], ['releases_rt', 'release_files_rt'])) {
|
||||
exit('Argument1 is the index name, currently only releases_rt/release_files_rt are supported.'.PHP_EOL);
|
||||
}
|
||||
(new SphinxSearch())->optimizeRTIndex($argv[1]);
|
||||
(new SphinxSearch())->optimizeRTIndex();
|
||||
|
||||
@@ -2,13 +2,10 @@
|
||||
|
||||
require_once dirname(__DIR__, 2).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use nntmux\db\DB;
|
||||
use App\Models\Release;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use nntmux\SphinxSearch;
|
||||
use nntmux\ReleaseSearch;
|
||||
|
||||
if (NN_RELEASE_SEARCH_TYPE !== ReleaseSearch::SPHINX) {
|
||||
exit('Error, NN_RELEASE_SEARCH_TYPE in nntmux/config/settings.php must be set to SPHINX!'.PHP_EOL);
|
||||
}
|
||||
if (! isset($argv[1]) || $argv[1] !== 'releases_rt') {
|
||||
exit(
|
||||
"Argument 1 is the index name, releases_rt are the only supported ones currently.\n".
|
||||
@@ -25,10 +22,9 @@ if (! isset($argv[1]) || $argv[1] !== 'releases_rt') {
|
||||
// Bulk insert releases into sphinx RT index.
|
||||
function populate_rt($table, $max)
|
||||
{
|
||||
$pdo = new DB();
|
||||
|
||||
if ($table === 'releases_rt') {
|
||||
$pdo->queryDirect('SET SESSION group_concat_max_len=16384');
|
||||
DB::unprepared('SET SESSION group_concat_max_len=16384;');
|
||||
DB::commit();
|
||||
$query = 'SELECT r.id, r.name, r.searchname, r.fromname, IFNULL(GROUP_CONCAT(rf.name SEPARATOR " "),"") filename
|
||||
FROM releases r
|
||||
LEFT JOIN release_files rf ON(r.id=rf.releases_id)
|
||||
@@ -37,7 +33,7 @@ function populate_rt($table, $max)
|
||||
ORDER BY r.id ASC
|
||||
LIMIT %d';
|
||||
$rtvalues = '(id, name, searchname, fromname, filename)';
|
||||
$totals = $pdo->queryOneRow('SELECT COUNT(id) AS c, MIN(id) AS min FROM releases');
|
||||
$totals = Release::query()->selectRaw('COUNT(id) AS c, MIN(id) AS min')->first();
|
||||
if (! $totals) {
|
||||
exit("Could not get database information for releases table.\n");
|
||||
}
|
||||
@@ -51,9 +47,10 @@ function populate_rt($table, $max)
|
||||
$string = sprintf('REPLACE INTO %s %s VALUES ', $table, $rtvalues);
|
||||
|
||||
$lastId = $minId - 1;
|
||||
echo "[Starting to populate sphinx RT index $table with $total releases.]\n";
|
||||
echo "[Starting to populate sphinx RT index $table with $total releases.]" . PHP_EOL;
|
||||
for ($i = $minId; $i <= ($total + $max + $minId); $i += $max) {
|
||||
$rows = $pdo->queryDirect(sprintf($query, $lastId, $max));
|
||||
$rows = DB::select(sprintf($query, $lastId, $max));
|
||||
DB::commit();
|
||||
if (! $rows) {
|
||||
continue;
|
||||
}
|
||||
@@ -68,10 +65,10 @@ function populate_rt($table, $max)
|
||||
$tempString .= sprintf(
|
||||
'(%d,%s,%s,%s,%s),',
|
||||
$row['id'],
|
||||
$sphinx->sphinxQL->escapeString($row['name']),
|
||||
$sphinx->sphinxQL->escapeString($row['searchname']),
|
||||
$sphinx->sphinxQL->escapeString($row['fromname']),
|
||||
$sphinx->sphinxQL->escapeString($row['filename'])
|
||||
$sphinx::escapeString($row['name']),
|
||||
$sphinx::escapeString($row['searchname']),
|
||||
$sphinx::escapeString($row['fromname']),
|
||||
$sphinx::escapeString($row['filename'])
|
||||
);
|
||||
break;
|
||||
}
|
||||
@@ -79,7 +76,8 @@ function populate_rt($table, $max)
|
||||
if (! $tempString) {
|
||||
continue;
|
||||
}
|
||||
$sphinx->sphinxQL->queryExec($string.rtrim($tempString, ','));
|
||||
DB::unprepared($string.rtrim($tempString, ','));
|
||||
DB::commit();
|
||||
echo '.';
|
||||
}
|
||||
echo "\n[Done]\n";
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once dirname(__DIR__, 2).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use nntmux\db\DB;
|
||||
use nntmux\ReleaseSearch;
|
||||
|
||||
if (! isset($argv[1]) || ! in_array($argv[1], ['sphinx', 'standard'])) {
|
||||
exit('Argument1 (required) is the method of search you would like to optimize for. Choices are sphinx or standard.'.PHP_EOL.
|
||||
'Argument2 (optional) is the storage engine and row_format you would like the release_search_data table to use. If not entered it will be left default.'.PHP_EOL.
|
||||
'Choices are (c|d)(myisam|innodb) (Compressed|Dynamic)(MyISAM|InnoDB) entered like dinnodb. This argument has no effect if optimizing for Sphinx.'.PHP_EOL.
|
||||
'Please stop all processing scripts before running this script.'.PHP_EOL);
|
||||
}
|
||||
|
||||
switch ($argv[1]) {
|
||||
case 'sphinx':
|
||||
if (NN_RELEASE_SEARCH_TYPE == ReleaseSearch::SPHINX) {
|
||||
optimizeForSphinx(new DB());
|
||||
} else {
|
||||
echo PHP_EOL.$pdo->log->error('Error, NN_RELEASE_SEARCH_TYPE in www/settings.php must be set to SPHINX to optimize for Sphinx!'.PHP_EOL);
|
||||
}
|
||||
break;
|
||||
case 'standard':
|
||||
revertToStandard(new DB());
|
||||
break;
|
||||
}
|
||||
|
||||
// Optimize database usage for Sphinx full-text
|
||||
function optimizeForSphinx($pdo)
|
||||
{
|
||||
echo PHP_EOL.$pdo->log->info('Dropping search triggers to save CPU and lower QPS. (Quick)'.PHP_EOL);
|
||||
dropSearchTriggers($pdo);
|
||||
|
||||
echo $pdo->log->info('Truncating release_search_data table to free up memory pools/buffers. (Quick)'.PHP_EOL);
|
||||
$pdo->queryExec('TRUNCATE TABLE release_search_data');
|
||||
|
||||
echo $pdo->log->header('Optimization for Sphinx process complete!'.PHP_EOL);
|
||||
}
|
||||
|
||||
//Revert database to standard schema
|
||||
function revertToStandard($pdo)
|
||||
{
|
||||
$engFormat = '';
|
||||
|
||||
if (isset($argv[2]) && in_array($argv[2], ['cinnodb', 'dinnodb', 'cmyisam', 'dmyisam'])) {
|
||||
switch ($argv[2]) {
|
||||
case 'cinnnodb':
|
||||
$engFormat = 'ENGINE = InnoDB ROW_FORMAT = Compressed';
|
||||
break;
|
||||
case 'dinnodb':
|
||||
$engFormat = 'ENGINE = InnoDB ROW_FORMAT = Dynamic';
|
||||
break;
|
||||
case 'cmyisam':
|
||||
$engFormat = 'ENGINE = MyISAM ROW_FORMAT = Compressed';
|
||||
break;
|
||||
case 'dmyisam':
|
||||
$engFormat = 'ENGINE = MyISAM ROW_FORMAT = Dynamic';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
echo PHP_EOL.$pdo->log->info('Dropping old table data and recreating fresh from schema. (Quick)'.PHP_EOL);
|
||||
$pdo->queryExec('DROP TABLE IF EXISTS release_search_data');
|
||||
$pdo->queryExec(
|
||||
sprintf(
|
||||
"
|
||||
CREATE TABLE release_search_data (
|
||||
id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
releases_id INT(11) UNSIGNED NOT NULL,
|
||||
guid VARCHAR(50) NOT NULL,
|
||||
name VARCHAR(255) NOT NULL DEFAULT '',
|
||||
searchname VARCHAR(255) NOT NULL DEFAULT '',
|
||||
fromname VARCHAR(255) DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
FULLTEXT INDEX ix_releasesearch_name_ft (name),
|
||||
FULLTEXT INDEX ix_releasesearch_searchname_ft (searchname),
|
||||
FULLTEXT INDEX ix_releasesearch_fromname_ft (fromname),
|
||||
INDEX ix_releasesearch_releases_id (releases_id),
|
||||
INDEX ix_releasesearch_guid (guid)
|
||||
)
|
||||
%s
|
||||
DEFAULT CHARSET = utf8
|
||||
COLLATE = utf8_unicode_ci
|
||||
AUTO_INCREMENT = 1",
|
||||
$engFormat
|
||||
)
|
||||
);
|
||||
|
||||
echo $pdo->log->info('Populating the releasearch table with initial data. (Slow)'.PHP_EOL);
|
||||
$pdo->queryInsert('INSERT INTO release_search_data (releases_id, guid, name, searchname, fromname)
|
||||
SELECT id, guid, name, searchname, fromname FROM releases');
|
||||
|
||||
echo $pdo->log->info('Adding the auto-population triggers. (Quick)'.PHP_EOL);
|
||||
|
||||
dropSearchTriggers($pdo);
|
||||
|
||||
$pdo->exec(
|
||||
'
|
||||
CREATE TRIGGER insert_search AFTER INSERT ON releases FOR EACH ROW
|
||||
BEGIN
|
||||
INSERT INTO release_search_data (releases_id, guid, name, searchname, fromname)
|
||||
VALUES (NEW.id, NEW.guid, NEW.name, NEW.searchname, NEW.fromname);
|
||||
END;
|
||||
|
||||
CREATE TRIGGER update_search AFTER UPDATE ON releases FOR EACH ROW
|
||||
BEGIN
|
||||
IF NEW.guid != OLD.guid
|
||||
THEN UPDATE release_search_data
|
||||
SET guid = NEW.guid
|
||||
WHERE releases_id = OLD.id;
|
||||
END IF;
|
||||
IF NEW.name != OLD.name
|
||||
THEN UPDATE release_search_data
|
||||
SET name = NEW.name
|
||||
WHERE releases_id = OLD.id;
|
||||
END IF;
|
||||
IF NEW.fromname != OLD.fromname
|
||||
THEN UPDATE release_search_data
|
||||
SET fromname = NEW.fromname
|
||||
WHERE releases_id = OLD.id;
|
||||
END IF;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER delete_search AFTER DELETE ON releases FOR EACH ROW
|
||||
BEGIN
|
||||
DELETE FROM release_search_data
|
||||
WHERE releases_id = OLD.id;
|
||||
END;'
|
||||
);
|
||||
echo $pdo->log->header('Standard search should once again be available.'.PHP_EOL);
|
||||
}
|
||||
|
||||
//Drops existing triggers
|
||||
function dropSearchTriggers($pdo)
|
||||
{
|
||||
$pdo->queryExec('DROP TRIGGER IF EXISTS insert_search');
|
||||
$pdo->queryExec('DROP TRIGGER IF EXISTS update_search');
|
||||
$pdo->queryExec('DROP TRIGGER IF EXISTS delete_search');
|
||||
}
|
||||
+1
-20
@@ -1114,32 +1114,13 @@ class NameFixer
|
||||
$join = '';
|
||||
|
||||
if (\strlen($preTitle) >= 15 && preg_match(self::PREDB_REGEX, $preTitle)) {
|
||||
switch (NN_RELEASE_SEARCH_TYPE) {
|
||||
case ReleaseSearch::SPHINX:
|
||||
|
||||
$titlematch = SphinxSearch::escapeString($preTitle);
|
||||
$join .= sprintf(
|
||||
'INNER JOIN releases_se rse ON rse.id = r.id
|
||||
WHERE rse.query = "@(name,searchname,filename) %s;mode=extended"',
|
||||
$titlematch
|
||||
);
|
||||
break;
|
||||
case ReleaseSearch::FULLTEXT:
|
||||
//Remove all non-printable chars from PreDB title
|
||||
preg_match_all('#[a-zA-Z0-9]{3,}#', $preTitle, $matches, PREG_PATTERN_ORDER);
|
||||
$titlematch = '+'.implode(' +', $matches[0]);
|
||||
$join .= sprintf(
|
||||
"INNER JOIN release_search_data rs ON rs.releases_id = r.id
|
||||
WHERE
|
||||
(MATCH (rs.name) AGAINST ('%1\$s' IN BOOLEAN MODE)
|
||||
OR MATCH (rs.searchname) AGAINST ('%1\$s' IN BOOLEAN MODE))",
|
||||
$titlematch
|
||||
);
|
||||
break;
|
||||
case ReleaseSearch::LIKE:
|
||||
// Do not add a JOIN for FT, let the query run in LIKE mode only (slow)
|
||||
$join .= 'WHERE 1=1 ';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $join;
|
||||
|
||||
@@ -738,14 +738,9 @@ class ReleaseRemover
|
||||
if ($this->crapTime === '') {
|
||||
$regexMatch = $this->extractSrchFromRegx($dbRegex);
|
||||
if ($regexMatch !== '') {
|
||||
switch (NN_RELEASE_SEARCH_TYPE) {
|
||||
case ReleaseSearch::SPHINX:
|
||||
$ftMatch = sprintf('rse.query = "@(name,searchname) %s;limit=1000000;maxmatches=1000000;mode=any" AND', str_replace('|', ' ', str_replace('"', '', $regexMatch)));
|
||||
break;
|
||||
case ReleaseSearch::FULLTEXT:
|
||||
$ftMatch = sprintf("(MATCH (rs.name) AGAINST ('%1\$s') OR MATCH (rs.searchname) AGAINST ('%1\$s')) AND", str_replace('|', ' ', $regexMatch));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -811,7 +806,7 @@ class ReleaseRemover
|
||||
);
|
||||
|
||||
if ($opTypeName === 'Subject') {
|
||||
$join = (NN_RELEASE_SEARCH_TYPE === ReleaseSearch::SPHINX ? 'INNER JOIN releases_se rse ON rse.id = r.id' : 'INNER JOIN release_search_data rs ON rs.releases_id = r.id');
|
||||
$join = 'INNER JOIN releases_se rse ON rse.id = r.id';
|
||||
} else {
|
||||
$join = '';
|
||||
}
|
||||
|
||||
@@ -41,19 +41,7 @@ class ReleaseSearch
|
||||
*/
|
||||
public function __construct(DB $settings)
|
||||
{
|
||||
switch (NN_RELEASE_SEARCH_TYPE) {
|
||||
case self::LIKE:
|
||||
$this->fullTextJoinString = '';
|
||||
break;
|
||||
case self::SPHINX:
|
||||
$this->fullTextJoinString = 'INNER JOIN releases_se rse ON rse.id = r.id';
|
||||
break;
|
||||
case self::FULLTEXT:
|
||||
default:
|
||||
$this->fullTextJoinString = 'INNER JOIN release_search_data rs on rs.releases_id = r.id';
|
||||
break;
|
||||
}
|
||||
|
||||
$this->fullTextJoinString = 'INNER JOIN releases_se rse ON rse.id = r.id';
|
||||
$this->sphinxQueryOpt = ';limit=10000;maxmatches=10000;sort=relevance;mode=extended';
|
||||
$this->pdo = $settings instanceof DB ? $settings : new DB();
|
||||
}
|
||||
@@ -73,21 +61,7 @@ class ReleaseSearch
|
||||
if ($forceLike) {
|
||||
return $this->likeSQL();
|
||||
}
|
||||
|
||||
switch (NN_RELEASE_SEARCH_TYPE) {
|
||||
case self::LIKE:
|
||||
$SQL = $this->likeSQL();
|
||||
break;
|
||||
case self::SPHINX:
|
||||
$SQL = $this->sphinxSQL();
|
||||
break;
|
||||
case self::FULLTEXT:
|
||||
default:
|
||||
$SQL = $this->fullTextSQL();
|
||||
break;
|
||||
}
|
||||
|
||||
return $SQL;
|
||||
return $this->sphinxSQL();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,39 +73,6 @@ class ReleaseSearch
|
||||
return $this->fullTextJoinString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create SQL sub-query for full text searching.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function fullTextSQL(): string
|
||||
{
|
||||
$return = '';
|
||||
foreach ($this->searchOptions as $columnName => $searchString) {
|
||||
$searchWords = '';
|
||||
|
||||
// At least 1 search term needs to be mandatory.
|
||||
$words = explode(' ', (! preg_match('/[+!^]/', $searchString) ? '+' : '').$searchString);
|
||||
foreach ($words as $word) {
|
||||
$word = str_replace(['!', '^', "'"], ['+', '+', "'"], trim($word, "\n\t\r\0\x0B- "));
|
||||
|
||||
if ($word !== '' && $word !== '-' && \strlen($word) > 1) {
|
||||
$searchWords .= ($word.' ');
|
||||
}
|
||||
}
|
||||
$searchWords = trim($searchWords);
|
||||
if ($searchWords !== '') {
|
||||
$return .= sprintf(" AND MATCH(rs.%s) AGAINST('%s' IN BOOLEAN MODE)", $columnName, $searchWords);
|
||||
}
|
||||
}
|
||||
// If we didn't get anything, try the LIKE method.
|
||||
if ($return === '') {
|
||||
return $this->likeSQL();
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create SQL sub-query for standard search.
|
||||
*
|
||||
|
||||
+50
-75
@@ -2,15 +2,27 @@
|
||||
|
||||
namespace nntmux;
|
||||
|
||||
use nntmux\db\DB;
|
||||
use App\Models\Release;
|
||||
use Foolz\SphinxQL\Drivers\Pdo\Connection;
|
||||
use Foolz\SphinxQL\Helper;
|
||||
use Foolz\SphinxQL\SphinxQL;
|
||||
|
||||
class SphinxSearch
|
||||
{
|
||||
/**
|
||||
* SphinxQL connection.
|
||||
* @var DB
|
||||
* @var \Foolz\SphinxQL\SphinxQL
|
||||
*/
|
||||
public $sphinxQL = null;
|
||||
public $sphinxQL;
|
||||
|
||||
/**
|
||||
* @var \Foolz\SphinxQL\Drivers\Pdo\Connection
|
||||
*/
|
||||
protected $connection;
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Config\Repository|mixed
|
||||
*/
|
||||
protected $index;
|
||||
|
||||
/**
|
||||
* Establish connection to SphinxQL.
|
||||
@@ -19,25 +31,10 @@ class SphinxSearch
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if (NN_RELEASE_SEARCH_TYPE === ReleaseSearch::SPHINX) {
|
||||
if (! defined('NN_SPHINXQL_HOST_NAME')) {
|
||||
define('NN_SPHINXQL_HOST_NAME', '0');
|
||||
}
|
||||
if (! defined('NN_SPHINXQL_PORT')) {
|
||||
define('NN_SPHINXQL_PORT', 9306);
|
||||
}
|
||||
if (! defined('NN_SPHINXQL_SOCK_FILE')) {
|
||||
define('NN_SPHINXQL_SOCK_FILE', '');
|
||||
}
|
||||
$this->sphinxQL = new DB(
|
||||
[
|
||||
'dbname' => '',
|
||||
'dbport' => NN_SPHINXQL_PORT,
|
||||
'dbhost' => NN_SPHINXQL_HOST_NAME,
|
||||
'dbsock' => NN_SPHINXQL_SOCK_FILE,
|
||||
]
|
||||
);
|
||||
}
|
||||
$this->connection = new Connection();
|
||||
$this->connection->setParams(['host' => config('sphinxsearch.host'), 'port' => config('sphinxsearch.port')]);
|
||||
$this->sphinxQL = SphinxQL::create($this->connection);
|
||||
$this->index = config('sphinxsearch.index');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,39 +44,29 @@ class SphinxSearch
|
||||
public function insertRelease($parameters): void
|
||||
{
|
||||
if ($this->sphinxQL !== null && $parameters['id']) {
|
||||
$this->sphinxQL->queryExec(
|
||||
sprintf(
|
||||
'REPLACE INTO releases_rt (id, name, searchname, fromname, filename) VALUES (%d, %s, %s, %s, %s)',
|
||||
$parameters['id'],
|
||||
self::escapeString($parameters['name']),
|
||||
self::escapeString($parameters['searchname']),
|
||||
self::escapeString($parameters['fromname']),
|
||||
empty($parameters['filename']) ? "''" : self::escapeString($parameters['filename'])
|
||||
)
|
||||
);
|
||||
$this->sphinxQL
|
||||
->replace()
|
||||
->into($this->index)
|
||||
->set(['id' => $parameters['id'], 'name' => $parameters['name'], 'searchname' => $parameters['searchname'], 'fromname' => $parameters['fromname'], 'filename' => empty($parameters['filename']) ? "''" : $parameters['filename']])
|
||||
->execute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete release from Sphinx RT tables.
|
||||
* @param array $identifiers ['g' => Release GUID(mandatory), 'id' => ReleaseID(optional, pass false)]
|
||||
* @param DB $pdo
|
||||
*/
|
||||
public function deleteRelease($identifiers, DB $pdo): void
|
||||
public function deleteRelease($identifiers): void
|
||||
{
|
||||
if ($this->sphinxQL !== null) {
|
||||
if ($identifiers['i'] === false) {
|
||||
$identifiers['i'] = $pdo->queryOneRow(
|
||||
sprintf('SELECT id FROM releases WHERE guid = %s', $pdo->escapeString($identifiers['g']))
|
||||
);
|
||||
if ($identifiers['i'] !== false) {
|
||||
$identifiers['i'] = $identifiers['i']['id'];
|
||||
}
|
||||
}
|
||||
if ($identifiers['i'] !== false) {
|
||||
$this->sphinxQL->queryExec(sprintf('DELETE FROM releases_rt WHERE id = %d', $identifiers['i']));
|
||||
if ($identifiers['i'] === false) {
|
||||
$identifiers['i'] = Release::query()->where('guid', $identifiers['g'])->first(['id']);
|
||||
if ($identifiers['i'] !== null) {
|
||||
$identifiers['i'] = $identifiers['i']['id'];
|
||||
}
|
||||
}
|
||||
if ($identifiers['i'] !== false) {
|
||||
$this->sphinxQL->delete()->from([$this->index])->where('id', '=', $identifiers['i']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,45 +92,33 @@ class SphinxSearch
|
||||
*/
|
||||
public function updateRelease($releaseID): void
|
||||
{
|
||||
if ($this->sphinxQL !== null) {
|
||||
$pdo = new DB();
|
||||
$new = $pdo->queryOneRow(
|
||||
sprintf(
|
||||
'
|
||||
SELECT r.id, r.name, r.searchname, r.fromname, IFNULL(GROUP_CONCAT(rf.name SEPARATOR " "),"") filename
|
||||
FROM releases r
|
||||
LEFT JOIN release_files rf ON (r.id=rf.releases_id)
|
||||
WHERE r.id = %d
|
||||
GROUP BY r.id LIMIT 1',
|
||||
$releaseID
|
||||
)
|
||||
);
|
||||
if ($new !== false) {
|
||||
$this->insertRelease($new);
|
||||
}
|
||||
$new = Release::query()
|
||||
->where('releases.id', $releaseID)
|
||||
->leftJoin('release_files as rf', 'releases.id', '=', 'rf.releases_id')
|
||||
->select(['releases.id', 'releases.name', 'releases.searchname', 'releases.fromname'])
|
||||
->selectRaw('IFNULL(GROUP_CONCAT(rf.name SEPARATOR " "),"") filename')
|
||||
->groupBy('releases.id')
|
||||
->first();
|
||||
|
||||
if ($new !== null) {
|
||||
$this->insertRelease($new);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate a RT index.
|
||||
* @param string $indexName
|
||||
* Truncate the RT index.
|
||||
*/
|
||||
public function truncateRTIndex($indexName): void
|
||||
public function truncateRTIndex(): void
|
||||
{
|
||||
if ($this->sphinxQL !== null) {
|
||||
$this->sphinxQL->queryExec(sprintf('TRUNCATE RTINDEX %s', $indexName));
|
||||
}
|
||||
Helper::create($this->connection)->truncateRtIndex($this->index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimize a RT index.
|
||||
* @param string $indexName
|
||||
* Optimize the RT index.
|
||||
*/
|
||||
public function optimizeRTIndex($indexName): void
|
||||
public function optimizeRTIndex(): void
|
||||
{
|
||||
if ($this->sphinxQL !== null) {
|
||||
$this->sphinxQL->queryExec(sprintf('FLUSH RTINDEX %s', $indexName));
|
||||
$this->sphinxQL->queryExec(sprintf('OPTIMIZE INDEX %s', $indexName));
|
||||
}
|
||||
Helper::create($this->connection)->flushRtIndex($this->index);
|
||||
Helper::create($this->connection)->optimizeIndex($this->index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +123,6 @@ class Configure
|
||||
\define('NN_FLOOD_WAIT_TIME', 5);
|
||||
\define('NN_FLOOD_MAX_REQUESTS_PER_SECOND', 5);
|
||||
\define('NN_USE_SQL_TRANSACTIONS', true);
|
||||
\define('NN_RELEASE_SEARCH_TYPE', 0);
|
||||
\define('NN_MAX_PAGER_RESULTS', '125000');
|
||||
}
|
||||
unset($settings_file);
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
* and $current_settings_file_version in nntmux\config\Configure.php
|
||||
* @version 7
|
||||
*/
|
||||
define('NN_SETTINGS_FILE_VERSION', 7);
|
||||
define('NN_SETTINGS_FILE_VERSION', 8);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////// Web Settings //////////////////////////////////////////////////////////
|
||||
@@ -72,44 +72,6 @@ define('NN_FLOOD_WAIT_TIME', 5);
|
||||
*/
|
||||
define('NN_FLOOD_MAX_REQUESTS_PER_SECOND', 5);
|
||||
|
||||
/*
|
||||
* The type of search system to use on the site.
|
||||
*
|
||||
* 0 = The default system, which uses fulltext indexing (very fast but search results can be unexpected).
|
||||
* 1 = The old search system from newznab classic (much slower but produces better search results).
|
||||
* 2 = Search using sphinx real time index, see misc/sphinxsearch/README.md for installation details.
|
||||
*
|
||||
* @default 0
|
||||
*/
|
||||
define('NN_RELEASE_SEARCH_TYPE', 0);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////// Sphinx Settings ////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
* This is the hostname to use when connecting to the SphinxQL server,
|
||||
*
|
||||
* @note Using localhost / 127.0.0.1 has caused me issues and only 0 worked on my local server.
|
||||
* @note See misc/sphinxsearch/README.md for installation details.
|
||||
* @default '0'
|
||||
*/
|
||||
define('NN_SPHINXQL_HOST_NAME', '0');
|
||||
|
||||
/*
|
||||
* This is the port to the SphinxQL server.
|
||||
*
|
||||
* @default 9306
|
||||
*/
|
||||
define('NN_SPHINXQL_PORT', 9306);
|
||||
|
||||
/*
|
||||
* This is the (optional) location to the SphinxQL server socket file, if you set the "listen" setting to a sock file.
|
||||
*
|
||||
* @default ''
|
||||
*/
|
||||
define('NN_SPHINXQL_SOCK_FILE', '');
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////// CLI Settings //////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -326,6 +288,7 @@ if (extension_loaded('xdebug')) {
|
||||
* //////////////////////////////////////////////// Change log ////////////////////////////////////////////////////////////
|
||||
* ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
*
|
||||
*2018-02-08 v8 Remove search settings, sphinx is the only supported search engine
|
||||
* 2017-12-21 v7 Remove custom logging settings, Laravel is handling errors now
|
||||
* 2017-10-11 v6 Remove settings for PHP web/CLI SAPI's as these are now handled by Laravel
|
||||
* 2015-08-26 v4 Add settings for PHP web/CLI SAPI's.
|
||||
|
||||
+3
-17
@@ -159,21 +159,9 @@ if (isset($_REQUEST['searchadvr']) && ! isset($_REQUEST['id']) && ! isset($_REQU
|
||||
);
|
||||
}
|
||||
|
||||
switch (NN_RELEASE_SEARCH_TYPE) {
|
||||
case ReleaseSearch::FULLTEXT:
|
||||
$search_description =
|
||||
'MySQL Full Text Search Rules:<br />
|
||||
A leading exclamation point(! in place of +) indicates that this word must be present in each row that is returned.<br />
|
||||
A leading minus sign indicates that this word must not be present in any of the rows that are returned.<br />
|
||||
By default (when neither + nor - is specified) the word is optional, but the rows that contain it are rated higher.<br />
|
||||
See <a target="_blank" href=\'http://dev.mysql.com/doc/refman/5.0/en/fulltext-boolean.html\'>docs</a> for more operators.';
|
||||
break;
|
||||
case ReleaseSearch::LIKE:
|
||||
$search_description = 'Include ^ to indicate search must start with term, -- to exclude words.';
|
||||
break;
|
||||
case ReleaseSearch::SPHINX:
|
||||
default:
|
||||
$search_description =
|
||||
|
||||
|
||||
$search_description =
|
||||
'Sphinx Search Rules:<br />
|
||||
The search is case insensitive.<br />
|
||||
All words must be separated by spaces.
|
||||
@@ -188,8 +176,6 @@ Putting a * after a word will do a partial word search. ie: fish* will match fis
|
||||
If your search is only words seperated by spaces, all those words will be mandatory, the order of the words is not important.<br />
|
||||
You can enclose words using paranthesis. ie: (^game*|^dex*)s03*(x264<<nogrp$)<br />
|
||||
You can combine some of these rules, but not all.<br />';
|
||||
break;
|
||||
}
|
||||
|
||||
$page->smarty->assign(
|
||||
[
|
||||
|
||||
Reference in New Issue
Block a user