PHP

Релевантный поиск на php

Хочу поделиться с Вами, как можно сделать более менее хороший релевантный поиск по сайту с помощью php в связке с mysql.

Я видел много сайтов, на которых поиск идет по средствам деления фразы на слова и выводились результаты не те, которые нужны пользователю. Я решил написать скрипт, который будет выдавать результаты в более релевантном порядке.

Структура базы

В базе мы создадим несколько таблиц:

1. Страница контента:
CREATE TABLE `content` (
    `page_id` INT NOT NULL AUTO_INCREMENT ,
    `page_name` TEXT NOT NULL ,
    `page_curl` TEXT NOT NULL ,
    `page_text` TEXT NOT NULL ,
    `page_views` INT NOT NULL ,
    PRIMARY KEY ( `page_id` ) ,
    UNIQUE (
        `page_id`
    )
) ENGINE = MYISAM ;

2. Страница запросов
CREATE TABLE `search_words` (
    `word_id` INT NOT NULL AUTO_INCREMENT ,
    `word_words` TEXT NOT NULL ,
    `word_count` INT NOT NULL ,
    PRIMARY KEY ( `word_id` ) ,
    UNIQUE (
        `word_id`
    )
) ENGINE = MYISAM ;

После того как мы создали таблицы делаем php код:

1. Принять и почистить данные:
Все данные я привык передавать методом POST для того, чтобы никто не менял адресную строку. Фраза, которую ищет пользователь будет храниться в переменно: $_POST[«words»].

Для начала нам нужно поставить защиту от нежелательных атак:
function clean_post_data($data){
    $data = strip_tags($data);
    $data = strtolower($data);
    $data = preg_replace('~[^a-z0-9 \x80-\xFF]~i', "",$data); 
    return $data;
}

Данная функция чистить все ненужное из текста.

Вторым шагом мы создадим функцию которая позволит создать массив с нужными для поиска словами:
function clean_array_to_search($words = array(), $max = 0, $min_length){
    $result = array();
    $i = 0;
    foreach($words as $key => $value){
        if(strlen(trim($value)) >= $min_length){
            $i++;
            if($i <= $max){
                $result[] = trim($value);
            }
        }
    }
    return $result;
}

Третьим шагом мы составим функцию, которая будет выбирать из базы данных страницы, которые подходят под поисковую фразу:
function get_results($words){
    $sql = "SELECT * FROM (`content`) WHERE ";
    $i = 0;
    foreach($words as $key => $value){
        $i++;
        $sql = $sql." `page_name` LIKE '%".$value."%' OR `page_text` LIKE '%".$value."%'".($i==count($words)?"":" OR");
    }
    $sql .= " ORDER BY `page_views` DESC";
    $result = mysql_query($sql);
    while($row = @mysql_fetch_object($result)){
        $return = $row;
    }
    return $return;
}

После того, как мы получили массив с данными нам нужно отсортировать его с помощью функции:
function get_matches($content, $word = array()){
    $matches = array();
    foreach($content as $p){
        $res[$p->page_id] = $p;
        foreach($word as $w){
            if(trim($w) != ""){
                $w = trim($w);
                $matches[$p->page_id] = $matches[$p->page_id] + count(explode($w, $p->page_name));
                $matches[$p->page_id] = $matches[$p->page_id] + count(explode($w, $p->page_text));
            }
        }
    }
    arsort($matches);
    $i = 0;
    foreach($matches as $k => $v){
        $result[$i] = $res[$k];
        $result[$i]->matches = $v;
        $i++;
    }
    return $result;
}

В результате, чтобы сделать поиск нам нужно сделать следующее:
    $max = 10; // максимальное количество слов во фразе
    $min_length = 3; // минимальная длина искомого слова
    $word = explode(" ", clean_post_data($_POST["word"]));
    $words = clean_array_to_search($word, $max, $min_length);
    $results = get_results($words);
    $result = get_matches($results, $words);

Мы получили список того, что пользователь искал, причем в нужном ему порядке.
В самом начале я говорил, что данные я передаю методом POST поэтому нужно выполнить еще пару команд, чтобы можно было видеть результаты поиска:
function insert_into_search_table($words = array()){
    $words = implode(" ", $words);
    $sql = "INSERT INTO `search_words` (`word_id`, `word_words`) VALUES (NULL, '".$words."');";
    mysql_query($sql);
    return intval(mysql_insert_id());
}

В самый верх страницы мы вставим следующую строку, для того, чтобы любой, пройдя по ссылке мог получить те результаты которые получил ранее:
    if(isset($_GET["words_id"]) AND $_GET["words_id"] != "" AND $_GET["words_id"] == intval($_GET["words_id"])){
        $row = mysql_query("SELECT * FROM `search_words` WHERE `word_id` = '".intval($_GET["words_id"])."';");
        $row = @mysql_fetch_array($row);
        $_POST["word"] = $row["word_words"];
    }

В общем все, в итоге вы получаете массив с объектами: $result.
Жду комментариев, мнения о данной системе поиска, предложений по ее улучшению
Добавлено: 03 Сентября 2013 09:38:10 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...