I am very new to Drupal and attempting to build a module that will allow admins to tag nodes with keywords to boost nodes to the top of the search results.
I have a separate DB table for the keywords and respective node IDs. This table is UNIONed with the search_index table via hook_query_alter...
function mos_search_result_forcer_query_alter(QueryAlterableInterface &$query) {
if (get_class($query) !== 'PagerDefault') { //<< check this because this function will mod all queries elsewise
return;
}
// create unioned search index result set...
$index = db_select('search_index', 's');
$index->addField('s', 'sid');
$index->addField('s', 'word');
$index->addField('s', 'score');
$index->addField('s', 'type');
$msrfi = db_select('mos_search_result_forcer', 'm');
$msrfi->addField('m', 'nid', 'sid');
$msrfi->addField('m', 'keyword', 'word');
$msrfi->addExpression('(SELECT MAX(score) + m.id / (SELECT MAX(id) FROM {mos_search_result_forcer}) FROM {search_index})', 'score');
$msrfi->addExpression(':type', 'type', array(':type' => 'node'));
$index->union($msrfi);
$tables =& $query->getTables();
$tables['i']['table'] = $index;
return $query;
}
Drupal then generates the almost correct query...
SELECT
i.type AS type, i.sid AS sid, SUM(CAST('10' AS DECIMAL) * COALESCE(( (12.048628015788 * i.score * t.count)), 0) / CAST('10' AS DECIMAL)) AS calculated_score
FROM (
SELECT
s.sid AS sid, s.word AS word, s.score AS score, s.type AS type
FROM
search_index s
UNION SELECT
m.nid AS sid, m.keyword AS word, (
SELECT
MAX(score) + m.id / (SELECT MAX(id) FROM mos_search_result_forcer)
FROM
search_index
) AS score, 'node' AS type
FROM
mos_search_result_forcer m
) i
INNER JOIN node n ON n.nid = i.sid
INNER JOIN search_total t ON i.word = t.word
INNER JOIN search_dataset d ON i.sid = d.sid AND i.type = d.type
WHERE (n.status = '1')
AND( (i.word = 'turtles') )
AND (i.type = 'node')
/* this is the problem line... */
AND( (d.data LIKE '% turtles %' ESCAPE '\\') )
/* ...end problem line */
GROUP BY i.type, i.sid
HAVING (COUNT(*) >= '1')
ORDER BY calculated_score DESC
LIMIT 10 OFFSET 0
...I need that "problem line" to read...
AND( (d.data LIKE '% turtles %' ESCAPE '\\') OR (d.sid IN (SELECT nid FROM mos_search_result_forcer)) )
...what hook can I use to add that OR condition?
Thanks, smart people!
The following recommendations will help you in your SQL tuning process.
You'll find 3 sections below:
ALTER TABLE `mos_search_result_forcer` ADD INDEX `mos_result_idx_id` (`id`);
ALTER TABLE `node` ADD INDEX `node_idx_status` (`status`);
ALTER TABLE `search_dataset` ADD INDEX `search_dataset_idx_sid_type` (`sid`,`type`);
ALTER TABLE `search_index` ADD INDEX `search_index_idx_word_type` (`word`,`type`);
ALTER TABLE `search_total` ADD INDEX `search_total_idx_word` (`word`);
SELECT
i.type AS type,
i.sid AS sid,
SUM(CAST('10' AS DECIMAL) * COALESCE(((12.048628015788 * i.score * t.count)),
0) / CAST('10' AS DECIMAL)) AS calculated_score
FROM
(SELECT
s.sid AS sid,
s.word AS word,
s.score AS score,
s.type AS type
FROM
search_index s
WHERE
(
s.word = 'turtles'
)
AND (
s.type = 'node'
)
UNION
SELECT
m.nid AS sid,
m.keyword AS word,
(SELECT
MAX(score) + m.id / (SELECT
MAX(mos_search_result_forcer.id)
FROM
mos_search_result_forcer)
FROM
search_index) AS score,
'node' AS type
FROM
mos_search_result_forcer m) i
INNER JOIN
node n
ON n.nid = i.sid
INNER JOIN
search_total t
ON i.word = t.word
INNER JOIN
search_dataset d
ON i.sid = d.sid
AND i.type = d.type
WHERE
(
n.status = '1'
)
AND (
(
1 = 1
)
)
AND (
1 = 1
)
AND (
(
d.data LIKE '% turtles %' ESCAPE '\\'
)
)
GROUP BY
d.type,
d.sid
HAVING
(
COUNT(*) >= '1'
)
ORDER BY
calculated_score DESC LIMIT 10 OFFSET 0