Проверка на дубли

Тема в разделе "PHP", создана пользователем KillDead, 22 сен 2015.

Модераторы: latteo
  1. KillDead

    KillDead

    Регистр.:
    11 авг 2006
    Сообщения:
    884
    Симпатии:
    540
    Здравствуйте. Возникла небольшая задача, вроде бы тривиальная:
    Есть дорвей, требования к скрипту должны быть не особо большими. Mysql использовать нельзя. Дор получает и парсит новости, затем всё кеширует. Но проблема такая- нужно проверять, есть ли новость с заголовком "ХХХ1" уже на сайте или нет. Особо не думая сделал файл base.db в которой храню md5 всех новостей. Проверка представляет собой чтение всей базы в ключи массива и потом проверка, есть ли такой ключ.
    Код:
    $fp = fopen(  '/video_id.db', 'r');
    $_idbase = array();
    while ($idInBase = fgets($_idbasefp)) {
        $_idbase[trim($idInBase)] = 1;
    }
    fclose($_idbasefp);
    foreach($news as $title=>$__){
    if(isset(  $_idbase[$title])){
    continue;
    }
    
    }
    
    В принципе, всё устраивало, скорость нормальная, но при увеличении объёмов увеличилось количество памяти на массив, по рассчётам, скрипт будет есть аж 500 метров при максимальном наполнении.
    Хочу спросить- как лучше организовать такую проверку. Может ктото решал? Есть пара идей, но пока они под обдумыванием.
     
  2. ykpon

    ykpon

    Регистр.:
    8 дек 2012
    Сообщения:
    248
    Симпатии:
    143
    Sqlite?
     
    Nei, KillDead и Горбушка нравится это.
  3. Denixxx

    Denixxx

    Регистр.:
    7 фев 2014
    Сообщения:
    247
    Симпатии:
    191
    Юзал длительное время движки без БД, некоторые сайты и сейчас на них стоят.
    При использовании текстовых баз с индексом в 1 файле тормоза на разных хостингах начинаются, когда в базе примерно от 500 индексов.
    Решение обычно в разбитии новостей на блоки (например на категории или помесячно) до 300 новостей.
    Тогда нагрузка даже при большой посещаемости редко превышает 10Мб.
    Например: Новости, Новости август 2015, Новости сентябрь 2015, Архивы за 2014 и т.д.
     
    KillDead нравится это.
  4. KillDead

    KillDead

    Регистр.:
    11 авг 2006
    Сообщения:
    884
    Симпатии:
    540
    А как проверять на дубли? Читать все эти файлы?
    Пока что два варинта без использования сторонних либ
    1. Делаем md5 и создаём файл /a/b/c/abc.... Получится такой индексный кеш на файловой системе. Недостаток- хардам может быть не особо хорошо.
    2. Делаем разбивку индексного файла по 3-м (или 2-м) певым буквам кеша. То есть aa.db ab.db . Посчитал, если 1кк значений то в каждом будет ~4к для 2-х букв и ~200 для 3-х букв. Скорость тоже не страдает особо. Есдинственное, что для проверки придётся считывать обязательно один файл полностью.
     
    Denixxx нравится это.
  5. Denixxx

    Denixxx

    Регистр.:
    7 фев 2014
    Сообщения:
    247
    Симпатии:
    191
    Примерно при кешировании так и делал по первому варианту, только сохранял всё в одной папке.
    Что конечно не айс — при большом количестве файлов в папке кеша системе может стать плохо.
    Вот класс для кеширования в мд5 https://github.com/Den1xxx/ReloadCMS/blob/master/modules/engine/cache.php
    Собственно при заходе на сайт вызывается класс кеша и текущая страница перед выдачей в браузер сохраняется тупо на диск.
    А адрес страницы шифруется в мд5 и с этим именем сохраняется в папку кеша.
    При повторном заходе на эту страницу вычисляется — истек ли срок обновления кеша.
    Если срок истек, кеш пишется заново, если нет — движок не грузится вообще, а выдается страница с кеша.
    Вот вариант использования
    PHP:
    //Включаем кеш для незарегистрированных или если можно включать или если выводимый модуль не в списке исключений из кеша
    if (is_guest() && !empty($system->config['cache']) && !in_array($mod,explode("\n",str_replace("\r"''$system->config['disable_cache'])))){
    $cache = new CACHE;
    $cache -> start_cache();
    $cache -> time_file_cache $system->config['cache'];//
    if (!$cache -> is_fresh())    {
    rcms_start();
    $cache -> save_cache();
    }
    $cache -> clear_cache();
    if (
    $cache -> show_cache()) echo $cache -> CONTENT;
    } else {
    rcms_start();
    }
    Второй Ваш вариант — это собственно Гит так работает (разбивает на папки). Это ещё лучше.
     
  6. Nei

    Nei Nosce te ipsum

    Регистр.:
    5 сен 2009
    Сообщения:
    608
    Симпатии:
    479
    Чем sqlite плох?
     
  7. Андрей Шпак

    Андрей Шпак Создатель

    Регистр.:
    11 фев 2013
    Сообщения:
    43
    Симпатии:
    7
    :-] У вас же не один хостинг(сервер)? Храните хеши на другом, ненагруженном , с MySQL, а с дорвея отправляйте туда XML с новыми хешами, там принимающий скрипт делает проверку, вносит в базу новые, и отправляет назад XML с повторяющимися:crazy:
     
  8. latteo

    latteo Эффективное использование PHP, MySQL

    Moderator
    Регистр.:
    28 фев 2008
    Сообщения:
    1.450
    Симпатии:
    1.244
    Почитай https://github.com/yiisoft/yii2/issues/8549 надо лок файла делать и при чтении и при записи, иначи приколы при одновременном доступе к файлу от нескольких процессов...


    Мне такая реализация кеша понравилась https://github.com/yiisoft/yii2/blob/master/framework/caching/FileCache.php
    Разбивка по 2 символа на папку. При уровне в 2 директории по 2 символа будет нормально.
    Но такой кеш потом очень-очень сложно вычищать (даже при том что есть метод для чистки) и переносить между серверами практически анрил, если не VPS.

    Лучший вариант на мой вкус:
    - читаешь обалденную стать про то как работают индексы http://habrahabr.ru/company/mailru/blog/266811/
    - осознаешь, что так на файлах такое замутить будет непросто
    - и делаешь на базе какой-нибудь БД с возможностью индексов
     
    Denixxx, KillDead и ykpon нравится это.