Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP]Przetwarzanie dużych ilości tekstu
Forum PHP.pl > Forum > Przedszkole
jamaleq
Cześć.

Napisałem skrypt, który przyjmuje duże (nawet ogromne) ilości tekstu, na wejściu mam pliki po 256 MB (zmienna, którą można regulować, tu pokazane obrazowo).
Plik ładuję do zmienne przez
  1. serialize(file(plik)); (aktualnie, przy próbie pracy na stringach - wcześniej było bez serialize)
potem go przetwarzam. Muszę wyciągać po kilkaset słów, np. 500. Nie byłoby problemu, gdybym mógł te słowa przechowywać w tablicy, jednak przy takiej ilości danych tablice rozrastają się do nieakceptowalnych rozmiarów z punktu widzenia pamięci systemu. Po podzieleniu pliku na słowa, tablica 'zajmuje' ok. 8GB RAM przy dedyku z 32GB.

Rozwiązaniem jest korzystanie ze stringów, znalazłem pewne rozwiązanie, jednak nie chce działać tak, jak to założyłem.
Mianowicie:
  1. preg_replace( "/((?:\S*?\s){$this->_wordLimit})/", "$1", $this->_content);

Gdzie $_wordLimit to ograniczenie słów dla wyrażenia, a $_content to string z załadowaną zawartością pliku.

Rozwiązanie te prawie działa. Prawie, bo zamiast zwracać mi np. 500 pierwszych wyrazów, zwraca owego stringa bez tych wyrazów.

Próbowałem już różnych regex'ów, jednak nie udało mi się znaleźć odpowiedniego rozwiązania.

PS. Jeszcze raz zaznaczam, że operacje na tablicach odpadają.
PS2. Próbowałem też kombinować z zapisywaniem słów do bazy (SQLite3), jednak wydajność czasowa takiego rozwiązania jest tragiczna.
buliq
Czytaj plik linia po lini a nie całość na raz to nie będzie żarł tyle ramu

I pokaż co zwróci Ci ten kod:

  1. echo "$this->_wordLimit";
  2. echo "{$this->_wordLimit}";
  3. echo "{{$this->_wordLimit}}";
jamaleq
Fakt samego ładowania pliku nie zabiera tyle pamięci. Próbowałem już wczytywać linijka po linijce, nieznaczna różnica. Problem stanowi tu ładowanie danych to tablicy.
Co do outputów:
500
500
{500}
buliq
Widzisz już rozwiązanie? Czy powinienem Cię jeszcze nakierować?
jamaleq
Ok, to było moje niedopatrzenie.
Jednak problem dalej jest ten sam. preg_replace zwraca resztę, zamiast tych pierwszych x słów.
buliq
Bo używasz nie tej funkcji. Obecne działanie to takie:

  1. preg_replace("znajdz fragment tekstu", "zastap go tym tekstem", "szukaj i zastepuj tutaj");
  2.  


czyli on znajduje ci ten fragment tekstu i zastępuje dokładnie tym samym tekstem (parametr $1) ... może chodziło Ci o preg_match
jamaleq
Ok, teraz widzę błąd w moim myśleniu.
preg_match mnie nie ratuje, ponieważ zwraca bool'a, a ja potrzebuję wyciągnąć z tego stringa te pierwsze x znaków.
b4rt3kk
  1. preg_match($pattern, $string, $matches);
  2.  
  3. var_dump($matches);
Crozin
1. Jaki jest format pliku wejściowego? Masz nad nim kontrolę?
2. Co potrzebujesz zrobić z tymi danymi?
3. Potrzebujesz całość przetwarzać na raz, czy możesz to robić stopniowo, małymi paczkami?
jamaleq
@b4rt3kk,
spróbuję coś z tym zrobić.

Edit: tym sposobem pobieram pierwszy wynik z $matches, potem wrzucam go do tabeli, następnie usuwam z pierwotnego stringa za pomocą substr.
Póki co, przy 8 równoległych procesach przy plikach po 256MB zużycie pamięci nie przekracza 25%.

Edit2: jednak te rozwiązanie, podobnie jak te z bazą, znacznie wydłuża czas wczytywania pliku...

@Crozin,
1) bez formatu, plain text; generalnie, plik wejściowy ma 8+ GB, kroję go na pliki o wcześniej zdefiniowanym rozmiarze (np. 256MB) za pomocą exec(cut ~), wczytuję pokrojony plik jak w pierwszym poście, itd.
2) muszę z takiego 256MB pliku wrzucić to gdzieś, a następnie pokroić na wyrazy, po x wystąpień, a następnie te x wyrazów wrzucić do XML'a.
3) korzystam z pthreads (nawet działa), ale jeden plik = 1 proces, więc małe paczki raczej odpadają.

Jak już pisałem wcześniej, wrzucenie pojedynczych wyrazów to tablicy kończy się tym, że 1 x256MB plik zajmuje 1/4 całości RAM.
b4rt3kk
Zamiast do tablicy nie możesz od razu upychać tego do wyjściowego xml?
jamaleq
Teoretycznie mógłbym to zrobić, jednak wiązałoby się to ze znaczną zmianą kodu.
Jeżeli nic lepszego nie przyjdzie mi do głowy, będę musiał i z tym poeksperymentować.
b4rt3kk
Cytat(jamaleq @ 20.02.2015, 14:40:31 ) *
Teoretycznie mógłbym to zrobić, jednak wiązałoby się to ze znaczną zmianą kodu.
Jeżeli nic lepszego nie przyjdzie mi do głowy, będę musiał i z tym poeksperymentować.


Wg tego co piszesz to jedyne sensowne rozwiązanie, bo nie odkładasz niepotrzebnie danych do jakichś tablic, tylko robisz wszystko w locie.
jamaleq
@b4rt3kk,
Twoja propozycja wydaje się być najbardziej optymalnym rozwiązaniem. Na 8 procesów zużycie pamięci nie przekracza 7% zasobów.
Dodatkowo, dzielenie głównego pliku na znacznie mniejsze części (aktualnie 64MB) również znacznie poprawia wydajność.
Warto też dodać, że PHP z ZTS (pthreads tego wymaga) obniża wydajność PHP o ~15%. Jednak w tym przypadku pthreads znacznie przyspiesza całkowity czas wykonywania skryptu.

PS. Przepraszam, że dopiero teraz odpisuję. Temat można zamknąć.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.