2012-06-15 6 views
12

Ten tag został przeze mnie oznaczony jako WordPress, ale nie jestem do końca pewny, że jest to specyficzne dla WordPressa, więc publikuję go w StackOverflow, a nie WPSE. Rozwiązanie nie musi być specyficzne dla WordPress, po prostu PHP.Jak utworzyć efektywny filtr treści dla określonych postów?

Scenariusz
Prowadzę fishkeeping website z wielu tropikalnych ryb Species Profiles i Glossary wpisów.

Nasza strona internetowa koncentruje się wokół naszych profili. Są, jak można to nazwać, chlebem i masłem strony internetowej.

Mam nadzieję, że uda mi się osiągnąć to, że w każdym profilu gatunkowym, w którym wymieniony jest inny gatunek lub wpis słownika, mogę zamienić te słowa linkiem - na przykład zobaczysz here. Najlepiej byłoby, gdyby to miało miejsce również w wiadomościach, artykułach i postach na blogu.

Mamy prawie i 1700 glossary entries. Nasze profile gatunkowe są często długotrwałe i na koniec liczą się same nasze profile gatunków numbered more than 1.7 million words.

Co mam Obecnie Próba
Obecnie mam filter.php z funkcji, która - jak sądzę - nie to, co potrzebne do zrobienia. Kod jest dość długi i można go znaleźć w pełnej wersji: here.

Ponadto, w moim WordPress na functions.php, mam następujące: czy

# ============================================================================================== 
# [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')); 
    } 

The sposób to działa, jak (mam nadzieję) opisał komentarzy kodeksu, że każda godzina WordPress działa crona (który jest jak fałszywy cron - działa na trafienia użytkownika, ale to nie ma znaczenia, ponieważ czas nie jest ważny), który uruchamia filtr znaleziony powyżej.

Uzasadnieniem uruchomienia go co godzinę jest to, że jeśli spróbujemy uruchomić go po zapisaniu każdego posta, będzie to ze szkodą dla autora. Kiedy włączymy autorów gościnnych, nie jest to oczywiście do przyjęcia.

problem ...
Od miesięcy miewam problemy z tego filtru działa niezawodnie. Nie uważam, że problem leży w samym filtrze, ale w jednej z funkcji, które włączają filtr - np. Zadanie cron lub funkcja, która wybiera, które posty są filtrowane, lub funkcję, która przygotowuje listy słów itp. Dla filtr.

Niestety, zdiagnozowanie problemu jest dość trudne (co widzę), dzięki czemu działa w tle i tylko co godzinę. Próbowałem użyć funkcji WordPressa "update_option (która zasadniczo zapisuje prostą wartość bazy danych) do sprawdzania błędów, ale nie miałem dużo szczęścia - i szczerze mówiąc, jestem bardzo zdezorientowany, gdzie leży problem .

Zakończyliśmy umieszczanie strony na żywo bez tego filtra działającego poprawnie. Czasami wydaje się, że działa, czasami nie. W rezultacie mamy teraz całkiem sporo profili gatunków, które nie są poprawnie filtrowane.

Co chcę ...
Po prostu szukam porady na temat najlepszego sposobu uruchomienia tego filtru.

Czy praca Crona jest odpowiedzią? Mogę skonfigurować plik .php, który działa codziennie, co nie byłoby problemem. W jaki sposób określi, które posty muszą być filtrowane? Jaki wpływ miałby on na serwer w momencie jego uruchomienia?

Alternatywnie, czy strona administracyjna WordPress to odpowiedź? Gdybym wiedział, jak to zrobić, coś w rodzaju strony - wykorzystującej AJAX - która pozwoliłaby mi wybrać posty do uruchomienia filtra byłoby idealne. Istnieje wtyczka o nazwie AJAX Regenerate Thumbnails, która działa w ten sposób, może to byłoby najbardziej skuteczne?

Rozważania

  • Wielkość bazy danych/informacji zachorowanie/odczytu/napisane
  • które stanowiska są filtrowane
  • Wpływ filtr ma na serwerze; szczególnie biorąc pod uwagę, że nie wydaje mi się, że mogę zwiększyć limit pamięci WordPress w stosunku do 32 MB.
  • Czy sam filtr jest wydajny, skuteczny i niezawodny?

Jest to dość skomplikowane pytanie i mam nieuchronnie (jak byłem rozkojarzony około 18 razy przez kolegów w procesie) w lewo na kilka szczegółów. Zapraszam do sondowania mnie w celu uzyskania dalszych informacji.

Z góry dziękuję,

+0

Czy masz dostęp do swojej bazy danych SQL z zewnątrz? Jeśli niepokoi cię cron uruchomiony na twoim serwerze, możesz wykonać początkowy skrypt, który przetworzył twoje 1,5 miliona słów z komputera z skryptem PHP CLI, który jest podłączony do twojej bazy danych. –

+0

Nie ma związku: podczas przeglądania strony zauważyłem, że twoja struktura adresu URL jest ładnie przepisana. Jednak nie mogę nie zauważyć, że linki klasyfikacji są w formie '/ classification /% s', mimo że są dla zamówienia lub rodziny. Czy to jest zamierzone? Wygląda na to, że '/ classification/family /% s' i'/classification/order /% s' będzie mniej niejednoznaczne. –

+0

Dzięki za heads-up tam PhpMyCoder, dodam go do mojej (ciągle rosnącej!) Listy :) Obecnie nie zezwalam na zdalne połączenia z naszą bazą danych MySQL, ale mogę chwilowo na to zezwolić, a następnie uruchomić skrypt z mojego instalacja wampli. Czy ma duży wpływ na stronę internetową, jeśli baza danych jest zapisywana stale przez pewien czas? – dunc

Odpowiedz

5

Zrób to po utworzeniu profilu.

Spróbuj cofnąć cały proces. Zamiast sprawdzać treść słów, sprawdź słowa dla słów treści.

  1. Break publikować treści na wejściu do słów (na miejscu)
  2. wyeliminować duplikaty, te pod najmniejszym rozmiarze wyrazu w bazie danych, te ponad największym rozmiarze, a te w „zwykłych słów” listę, którą przechowujesz.
  3. Sprawdź przy każdej tabeli, czy niektóre tabele zawierają wyrażenia ze spacjami, wykonaj wyszukiwanie% text%, w przeciwnym razie wykonaj proste dopasowanie (znacznie szybciej) lub nawet zbuduj tabelę mieszania, jeśli naprawdę jest to duży problem. (Robiłbym to jako tablicę PHP i jakoś cache wynik, nie ma sensu wymyślać na nowo koła)
  4. Twórz linki z teraz znacznie mniejszymi listami.

Powinieneś być w stanie z łatwością zachować to poniżej 1 sekundy, nawet gdy wyprowadzasz się nawet do 100 000 słów, które sprawdzasz. Zrobiłem dokładnie to, bez buforowania list słów, dla filtra Bayesian wcześniej.

Z mniejszą listą, nawet jeśli jest chciwy i zbiera słowa, które nie pasują do "klauna" złapie "błazen klowka", wynikowa mniejsza lista powinna zawierać od kilku do kilkudziesięciu słów z linkami. Nie zajmie to czasu znalezienie znaleziska i zastąpienie go fragmentem tekstu.

Powyższe nie odnosi się w rzeczywistości do obaw dotyczących starszych profili.Nie mówisz dokładnie, ile tam jest, tylko że jest dużo tekstu i że jest on w 1400 do 3100 (oba elementy) razem wzięte. To starsze treści, które możesz zrobić na podstawie popularności, jeśli masz informacje. Lub w podanej dacie, najnowsze w pierwszej kolejności. Bez względu na to, najlepszym sposobem na zrobienie tego jest napisanie skryptu, który zawiesza limit czasu na PHP i tylko wsadowy - uruchamia ładunek/proces/zapis na wszystkich wpisach. Jeśli każdy zajmuje około 1 sekundy (prawdopodobnie znacznie mniej, ale najgorszy przypadek) mówisz 3100 sekund, czyli nieco mniej niż godzinę.

+0

Świetny wpis +1. Próbowałem wdrożyć twoje rozwiązanie dziś rano, ale napotkałem problem, który, jak podejrzewam, może spowolnić działanie. Niektóre terminy, których będę szukać, obejmują 'P. denisonii' i 'S. daemon' - skrócone nazwy gatunków. W związku z tym 'eksplodować' przez' "" 'nie będzie działać. Czy możesz polecić alternatywę? Nie mogę sobie wyobrazić, że przeszukiwanie każdego pola (np. "Dystrybucja", "siedlisko") dla wszystkich wyszukiwanych słów będzie skuteczne? – dunc

+0

Jeśli w bazie danych nie ma skróconego formularza, nie wiem, czy byłbyś w stanie wykryć skrócone wersje. Mianowicie, jeśli w bazie danych masz "Clown Loach", ale w tekście masz "C. Loach", nie widzę żadnego sposobu, aby poradzić sobie z tym skutecznie, chyba że masz pole w bazie danych (dla gatunku) dla krótkie wersje nazw. Ale jeśli się martwisz, ponieważ "C." wydaje się problematyczne, pamiętaj, że wyrzucasz słowa poniżej pewnego progu, a "% Loach%" w wyszukiwaniu LIKE pasuje do "Clown Loach", który mógłby mieć "C. Loach" w krótkim polu, dzięki czemu dostaniesz mecz. – DampeS8N

+0

Hmm, zastanawiam się, czy będę musiał wrócić do deski kreślarskiej. Gatunki ryb przyjmują jeden z dwóch formatów: 'Demon Satanoperca' lub' S. daemon', który - jeśli dobrze cię interpretuję - sprawi, że twój pomysł będzie trudny/niemożliwy? – dunc

Powiązane problemy