猿问

如何在全文搜索中处理多个搜索条件和优先级

是否可以以任何方式减少执行的查询?因为我现在这样做的方式还可以,但后来我可以得到 30 个查询,这对我来说看起来不太好


我的脚本


$string = 'new movie stars';

$words =  preg_split('/(\/|\s+)/', $string);

print_r($words);

数组( [0] => 新 [1] => 电影 [2] => 星星)


$sql = "SELECT * FROM movie WHERE MATCH(name) AGAINST('+$words[0] +$words[1] +$words[2]' IN BOOLEAN MODE)";

$query_name = $this->db->query($sql);


if ($query_name->num_rows < 20) {

$sql = "SELECT * FROM movie WHERE MATCH(name) AGAINST('+$words[0] +($words[1] $words[2])' IN BOOLEAN MODE)";

$query_name_two = $this->db->query($sql);

}


if (count($query_name->num_rows + $query_name_two->num_rows) < 20) {

$sql = "SELECT * FROM movie WHERE MATCH(name) AGAINST('$words[0] $words[1] $words[2]' IN BOOLEAN MODE)";

$query_name_three = $this->db->query($sql);

}


芜湖不芜
浏览 155回答 1
1回答

智慧大石

您的代码对SQL 注入相关的攻击是开放的。甚至real_escape_string无法完全保护它。请学习改用Prepared Statements。现在,除了上述建议之外,还有两个可能的进一步修复:修复 #1您用于将输入字符串标记为 FTS 单词的 php 代码不足。前段时间,我确实创建了一个函数来以更强大的方式处理这个需求。您可以改用以下内容:/**&nbsp;* Method to take an input string and tokenize it into an array of words for Full Text Searching (FTS).&nbsp;* This method is used when an input string can be made up of multiple words (let's say, separated by space characters),&nbsp;* and we need to use different Boolean operators on each of the words. The tokenizing process is similar to extraction&nbsp;* of words by FTS parser in MySQL. The operators used for matching in Boolean condition are removed from the input $phrase.&nbsp;* These characters as of latest version of MySQL (8+) are: +-><()~*:""&|&nbsp;* We can also execute the following query to get updated list: show variables like 'ft_boolean_syntax';&nbsp;* Afterwards, the modified string is split into individual words considering either space, comma, and, period (.) characters.&nbsp;* Details at: https://dev.mysql.com/doc/refman/8.0/en/fulltext-natural-language.html&nbsp;* @param string $phrase Input statement/phrase consisting of words&nbsp;* @return array Tokenized words&nbsp;* @author Madhur, 2019&nbsp;*/function tokenizeStringIntoFTSWords(string $phrase) : array {&nbsp; &nbsp; $phrase_mod = trim(preg_replace('/[><()~*:"&|+-]/', '', trim($phrase)));&nbsp; &nbsp; return preg_split('/[\s,.]/', $phrase_mod, null, PREG_SPLIT_NO_EMPTY);}修复 #2似乎您正在尝试通过按以下顺序给予优先级来对搜索进行排名:文本中的所有单词>第一个单词 AND 其余两个单词>中的任何一个 至少三个单词中的任何一个。但是,如果您阅读全文搜索文档,您可以使用相关性进行排序MATCH(),因为它还返回相关性分数。当MATCH()在WHERE子句中使用时,返回的行将自动以最高相关性优先排序(不幸的是,这仅适用于 NATURAL 模式,而不适用于 BOOLEAN 模式)。相关性值是非负浮点数。零相关性意味着没有相似性。相关性是根据行(文档)中的单词数、行中唯一单词的数量、集合中的单词总数以及包含特定单词的行数来计算的。所以基本上,文本中的所有单词已经比这三个单词中的任何一个都具有更高的相关性。现在,如果你需要给第一个词更高的优先级,你只需要>在第一个词上使用操作符。因此,您只需要以下单个查询:SELECT * FROM movie&nbsp;WHERE&nbsp;&nbsp; MATCH(name)&nbsp;&nbsp; AGAINST('>:first_word :second_word :third_word ..and so on)' IN BOOLEAN MODE)ORDER BY&nbsp;&nbsp; MATCH(name)&nbsp;&nbsp; AGAINST('>:first_word :second_word :third_word ..and so on)' IN BOOLEAN MODE)&nbsp;&nbsp; DESCLIMIT 20
随时随地看视频慕课网APP
我要回答