Вопрос по ajax, wordpress, cron, php – Как мне создать эффективный контент-фильтр для определенных постов?

12

Я отметил этот пост как WordPress, но я не совсем уверен, что он специфичен для WordPress, поэтому я публикую его в StackOverflow, а не в WPSE.The solution doesn't have to be WordPress-specific, simply PHP.

The Scenario
Я бегусайт по рыбному хозяйству с рядом тропических рыбSpecies Profiles а такжеGlossary записей.

Наш сайт ориентирован на наши профили. Они, как вы можете назвать, хлеб с маслом на сайте.

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

У нас есть почти1400 species profiles а также1700 glossary entries, Наши профили видов часто бывают длинными и, наконец, учитывают только наши профили видовnumbered more than 1.7 million words информации.

What I'm Currently Attempting
В настоящее время у меня естьfilter.php с функцией, которая, я считаю, делает то, что мне нужно. Код довольно длинный, и его можно найти полностьюВот.

Кроме того, в моей теме WordPressfunctions.phpУ меня есть следующее:

# ==============================================================================================
# [Filter]
#
# Every hour, using WP_Cron, `my_updated_posts` is checked. If there are new Post IDs in there,
# it will run a filter on all of the post's content. The filter will search for Glossary terms
# and scientific species names. If found, it will replace those names with links including a 
# pop-up.

    include "filter.php";

# ==============================================================================================
# When saving a post (new or edited), check to make sure it isn't a revision then add its ID
# to `my_updated_posts`.

    add_action( 'save_post', 'my_set_content_filter' );
    function my_set_content_filter( $post_id ) {
        if ( !wp_is_post_revision( $post_id ) ) {

            $post_type = get_post_type( $post_id );

            if ( $post_type == "species" || ( $post_type == "post" && in_category( "articles", $post_id ) ) || ( $post_type == "post" && in_category( "blogs", $post_id ) ) ) {
                //get the previous value
                $ids = get_option( 'my_updated_posts' );

                //add new value if necessary
                if( !in_array( $post_id, $ids ) ) {
                    $ids[] = $post_id;
                    update_option( 'my_updated_posts', $ids );
                }
            }
        }
    }

# ==============================================================================================
# Add the filter to WP_Cron.

    add_action( 'my_filter_posts_content', 'my_filter_content' );
    if( !wp_next_scheduled( 'my_filter_posts_content' ) ) {
        wp_schedule_event( time(), 'hourly', 'my_filter_posts_content' );
    }

# ==============================================================================================
# Run the filter.

    function my_filter_content() {
        //check to see if posts need to be parsed
        if ( !get_option( 'my_updated_posts' ) )
            return false;

        //parse posts
        $ids = get_option( 'my_updated_posts' );

        update_option( 'error_check', $ids );

        foreach( $ids as $v ) {
            if ( get_post_status( $v ) == 'publish' )
                run_filter( $v );

            update_option( 'error_check', "filter has run at least once" );
        }

        //make sure no values have been added while loop was running
        $id_recheck = get_option( 'my_updated_posts' );
        my_close_out_filter( $ids, $id_recheck );

        //once all options, including any added during the running of what could be a long cronjob are done, remove the value and close out
        delete_option( 'my_updated_posts' );
        update_option( 'error_check', 'working m8' );
        return true;
    }

# ==============================================================================================
# A "difference" function to make sure no new posts have been added to `my_updated_posts` whilst
# the potentially time-consuming filter was running.

    function my_close_out_filter( $beginning_array, $end_array ) {
        $diff = array_diff( $beginning_array, $end_array );
        if( !empty ( $diff ) ) {
            foreach( $diff as $v ) {
                run_filter( $v );
            }
        }
        my_close_out_filter( $end_array, get_option( 'my_updated_posts' ) );
    }

Способ, который (как мы надеемся) описали в комментариях к коду, заключается в том, что каждый час WordPress выполняет задание cron (которое похоже на ложный cron) - работает при попаданиях пользователя, но это не имеет значения, поскольку время не имеет значения. ; t важно), который запускает фильтр, найденный выше.

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

The Problem...
Уже несколько месяцев у меня возникают проблемы с надежной работой этого фильтра. Я не верю, что проблема связана с самим фильтром, но с одной из функций, которая включает фильтр, то есть заданием cron, или функцией, которая выбирает, какие посты фильтруются, или функцией, которая подготавливает списки слов и т. Д. Для фильтр.

К сожалению, диагностировать проблему довольно сложно (что я вижу), поскольку она работает в фоновом режиме и только ежечасно. Я пытался использовать WordPress.update_option функция (которая в основном записывает простое значение базы данных) для проверки ошибок, но мне не очень повезло - и, честно говоря, я совершенно запутался в том, где находится проблема.

Мы закончили работу сайта без корректной работы этого фильтра. Иногда кажется, что это работает, иногда это не так. В результате у нас теперь есть довольно много профилей видов, которые не были правильно отфильтрованы.

What I'd Like...
Я в основном ищу совет о том, как лучше всего использовать этот фильтр.

Является ли Cron Job ответом? Я могу настроить.php файл, который запускается каждый день, это не будет проблемой. Как бы он определил, какие сообщения нужно отфильтровать? Какое влияние это окажет на сервер во время его работы?

Альтернативно, является ли страница администратора WordPress ответом? Если бы я знал, как это сделать, то что-то похожее на страницу - с использованием AJAX - что позволило бы мне выбрать посты для запуска фильтра, было бы идеально. Есть плагин под названиемAJAX Regenerate Thumbnails который работает так, может быть, это будет наиболее эффективным?

Considerations

The size of the database/information being affected/read/written Which posts are filtered The impact the filter has on the server; especially considering I don't seem to be able to increase the WordPress memory limit past 32Mb. Is the actual filter itself efficient, effective and reliable?

Это довольно сложный вопрос, и я неизбежно (так как коллеги меня отвлекали примерно 18 раз в процессе) упустил некоторые детали. Пожалуйста, не стесняйтесь спрашивать меня для получения дополнительной информации.

Заранее спасибо,

Немного не связано: при поиске вокруг вашего сайта я заметил, что ваша структура URL-адресов хорошо переписана. Тем не менее, я не могу не заметить, что все ссылки классификации имеют вид/classification/%s несмотря на то, что для заказа или семьи. Это намеренно? Это похоже на/classification/family/%s а также/classification/order/%s будет менее двусмысленным. Bailey Parker
Я дал лишь один ответ и ваш код беглым взглядом, так что извините, если это уже было реализовано или предложено, но используете ли вы стоп-лист слов, чтобы не сравнивать с БД, например & quot ;, & quot; a & quot ;, так далее.? Bailey Parker
У вас есть доступ к вашей базе данных SQL из-за пределов? Если вы обеспокоены тем, что cron работает на вашем сервере, вы можете выполнить первоначальный запуск сценария, который обработал ваши 1,5 миллиона слов с компьютера, на котором запущен сценарий PHP CLI, подключенный к вашей базе данных. Bailey Parker
Это может произойти, хотя это окажет меньшее влияние, чем если бы вы делали всю обработку на месте. Единственный реальный удар, который может нанести ваш сервер, - это запросы UPDATE на БД. Если вы используете innodb в своей таблице сообщений (SHOW TABLE STATUS WHERE Name = 'table' проверить), попадание не будет ощущаться вообще, поскольку оно использует блокировку на уровне строк. Однако, если вы используете MyISAM, подумайте о запуске сценария CLI во время низкого трафика. Bailey Parker
Спасибо за хедз-ап PhpMyCoder, я добавлю его в свой (постоянно растущий!) Список :) В настоящее время я не разрешаю удаленные подключения к нашей базе данных MySQL, но я могу временно разрешить ему запускать сценарий из моего wamp монтаж. Будет ли это иметь большое влияние на веб-сайт, если база данных будет постоянно записываться в течение определенного периода времени? dunc

Ваш Ответ

1   ответ
5

Сделайте это, когда профиль будет создан.

Попробуйте полностью изменить процесс. Вместо проверки содержания для слов проверьте слова для слов содержания.

Break the content post on entry into words (on space) Eliminate duplicates, ones under the smallest size of a word in the database, ones over the largest size, and ones in a 'common words' list that you keep. Check against each table, if some of your tables include phrases with spaces, do a %text% search, otherwise do a straight match (much faster) or even build a hash table if it really is that big a problem. (I would do this as a PHP array and cache the result somehow, no sense reinventing the wheel) Create your links with the now dramatically smaller lists.

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

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

Вышесказанное не решает вашу проблему со старыми профилями. Вы не говорите точно, сколько их, только то, что текста много и что это 1400–3100 (оба пункта) вместе взятые. Этот старый контент вы можете сделать, основываясь на популярности, если у вас есть информация. Или по дате ввода, самое новое сначала. В любом случае, лучший способ сделать это - написать скрипт, который приостанавливает ограничение времени на PHP и просто запускает загрузку / обработку / сохранение для всех сообщений. Если каждая из них занимает около 1 секунды (вероятно, намного меньше, но в худшем случае), вы говорите 3100 секунд, что составляет чуть меньше часа.

Ах, конечно, я думаю, что я с тобой сейчас. Попробую - еще раз спасибо. dunc
Если в базе данных нет сокращенной формы, я не знаю, что вы сможете обнаружить сокращенные версии. А именно, если в базе данных у вас есть «Clown Loach» но в тексте у вас есть "C". Loach & quot ;, я не вижу никакого способа справиться с этим эффективно, если у вас нет поля в базе данных (для видов) для версий коротких имен. Но если вы волнуетесь, потому что "C." кажется проблематичным, помните, что вы отбрасываете слова ниже порога длины, и "% Loach%" в поиске LIKE будет соответствовать "Clown Loach" который мог бы иметь "C". Лоуч & Quot; в короткой области, таким образом, вы получите свое совпадение.
Хм, интересно, если мне придется вернуться к чертежной доске. Все виды рыб имеют один из двух форматов:Satanoperca daemon или жеS. daemonЧто, если я правильно вас интерпретирую, будет трудно / невозможно эффективно реализовать вашу идею? dunc
Отличный пост +1. Я пытался реализовать ваше решение сегодня утром, но столкнулся с проблемой, которая, как я подозреваю, может замедлить процесс. Некоторые из терминов, которые я буду искать, включаютP. denisonii а такжеS. daemon - сокращенные названия видов. В качестве таких,explode от" " не будет работать. Можете ли вы порекомендовать альтернативу? Я не могу себе представить, что поиск по каждому полю (т.е.distribution, habitat) по всем критериям поиска будет эффективно? dunc
Не верно @dunc, все, что вам нужно сделать, это включить дополнительное поле в таблицу видов с более короткой формой внутри. & quot; Демон & quot ;, поскольку он не работает в пространстве, загрузит всю рыбу с именем демона. Затем, когда вы делаете str_replace (), делайте это как с длинными, так и с короткими именами. Вы хотите, чтобы запрос возвращал хотя бы нужных рыб, но не всю таблицу рыб. Распределение пространства и выполнение% daemon%LIKE Полнотекстовый поиск вернет нужный элемент.

Похожие вопросы