| Autor | Zpráva | ||
|---|---|---|---|
| unlucky Profil |
#1 · Zasláno: 27. 3. 2013, 17:50:40
Mam soubor o velikosti 15Mb. Uvnitr je struktura:
@slovo /vyslovnost/ * slovni druh - vyznam1 - vyznam 2 =mozne slovni spojeni+ vyznam - dalsi vyznam =mozne slovni spojeni2+ dalsi vyznam2 !chytak - vyznam Dalsi... zatim mam toto: $soubor=file_get_contents("soubor.txt");
$lines = explode("\n", $soubor);
foreach ($lines as $line) {
$pos = strpos($line, "@");
if($pos===false){
echo "<br />vyznam: $line";
}else{
echo "<br />slovo: $line";
}
}Takto pres podminky zjistil, jestli je to vyznam, chytak ci dalsi mozne slovni spojeni. (pomoci stristr nebo strpos). Soubor bych nejspise rozdelil na mensi casti. Chci se zeptat, zda je s kodem vse v poradku a nelze ho nejak vylepsit |
||
| Tori Profil |
Řádek 6 se týká toho slovního spojení z ř.5, nebo samotného slova?
Totéž co file_get_contents + explode dělá i funkce file. Paměťově úspornější by bylo sekvenční čtení funkcí fgets. Nerozlišujete typ záznamu (první znak na řádku) - teda kromě slovo/ostatní. Místo strpos by šlo použít i pozici znaku v řetězci: $text = ltrim($line, '@*-=! ');
if($line{0} === '@')
echo "<br />slovo: $text";
elseif ($line{0} === '!')
echo "<br />pozor, chyták: $text";
elseif ($line{0} === '*')
echo "<br /><i>$text</i>";
else
echo "<br />význam: $text"; |
||
| unlucky Profil |
Prave, ze jsem chtel tyto data hodit do databaze. Zatim jsem to musel rozdelit na mensi soubory o velikosti 3Mb (zhruba 100 tisic radku). Struktura by vypadala takto:
tab word id, text tab interpretation word_id, meaning_id tab meaning id, text, type Tech jazyku bude daleko vice. A -> B, B -> A, A-> C, C->A atd.. Hlavnim jazykem bude A. Premyslim, zda nepouzit pro kazdy jazyk vlastni tabulky nebo jeden univerzalni (pridat sloupec smer do tab interpretation?), kdyz 1 jazyk/smer ma zhruba 250tis radku (vcetne vyznamu)= 12tis slov. Celkem souboru mam 9, tedy dohromady asi 2mil zaznamu, coz je celkem velke cislo. Nevim, co ocekavat a cemu se vyvarovat. Jeste se chci zeptat, jak ukladat tento radek: =mozne slovni spojeni2+ dalsi vyznam2 Nekdy ma slovo vice vyznamu z hlediska slovniho druhu: @show * podst. jmeno - predstaveni =show neco+ vyznam * sloveso - ukazat =show me+ ukaz mi |
||
| Tori Profil |
#4 · Zasláno: 28. 3. 2013, 07:45:10
A chcete to dělat spíš ve stylu slovniky.centrum.cz (cizí slovo -- jednoslovný ekvivalent), anebo jako TheFreeDictionary (cizí slovo -- delší popis významu)? V prvním případě by se to snad dalo řešit jednou velkou tabulkou slov ze všech jazyků, a vazební tabulkou, která propojí ekvivalenty. V druhém případě by se musely navíc rozlišovat i jednotlivé varianty významů (např. 1.tabule ve smyslu svislá deska + varianty: tabule na kterou se píše, okenní tabule; 2.tabule ve smyslu prostřeného stolu), protože pravděpodobně se v jiném jazyku řeknou každá jinak.
|
||
| unlucky Profil |
#5 · Zasláno: 28. 3. 2013, 12:02:05
Kdyz se na to tak divam, tak format dat ze souboru vypada jako freedict. Kazdopadne to budu ukladat jako 1 velkou tabulku se vsemi slovicky a pak kazdy vyznam/radek ukladat do druhe tabulky. Bude to jako to ma centrum. Jak jsem jiz psal, nevim, jak moc to bude problem s sql dotazy, kdyz tam bude zhruba 2 miliony radku v tabulce s vyznamy a 150 000 slovicek (zde pouziju naseptavac).
@show * podst. jmeno - predstaveni =show neco+ vyznam * sloveso - ukazat =show me+ ukaz mi show show neco show me jako 3 ruzna na sobe nezavisla slova nebo ty posledni 2 hodit do vyznamu |
||
| unlucky Profil |
Nakonec se mi podarilo dat dohromady tenhle kod. Soubor sice ma 500 tis. radku, ale v easyphp jsem nastavil exec timeout na par hod takze, snad za par hod bude vse ok.
<?php
header("Content-Type: text/html; charset=utf-8");
$db=@mysqli_connect("localhost","root","","xxx");
mysqli_query($db,"SET NAMES utf8");
date_default_timezone_set('Europe/Prague');
SetLocale(LC_ALL, "Czech");
$lines=file("testdata.txt");
$from_lang='en';
$to_lang='cs';
function insertni($text,$type,$word_id,$db,$add=''){
$from_lang='en';
$to_lang='cs';
$meaning=mysqli_real_escape_string($db,trim(strip_tags($text)));
mysqli_query($db,"insert into means (meaning,type,additional_meaning) values('$meaning','$type','$add')");
$meaning_id=@mysqli_insert_id($db);
mysqli_query($db,"insert into interpretation(word_id,meaning_id,from_lang,to_lang)
values('$word_id','$meaning_id','$from_lang','$to_lang')");
}
foreach ($lines as $line_nr => $line) {
//if($line_nr>185642){
$line=trim($line); //trim pro podminky
$text = ltrim($line, '@*-=! '); //trim prvni znaky pro pouziti
if(!empty($line)){
if($line{0} === '@'){//kdyz je slovo
$vyslovnost=explode("/",$text);
if(!isset($vyslovnost[1])){//kdyz neni vyslovnost
$vyslov='';
}else{
$vyslov=trim($vyslovnost[1]);
$text=trim($vyslovnost[0]);
}
//echo "<br /><br /><strong>$text</strong> vyslovnost: ".$vyslov;
$sql_text=mysqli_real_escape_string($db,strip_tags($text));
$check_word=mysqli_fetch_assoc(mysqli_query($db,"select id from word where word='$sql_text'"));
if($check_word['id']!=''){//kdyz existuje
$word_id=$check_word['id']; //ulozime id do promenne
}else{//kdyz neexistuje pridame a ulozime
$word=$sql_text;
$spelling=mysqli_real_escape_string($db,trim(strip_tags($vyslov)));
mysqli_query($db,"insert into word(word,lang,spelling) values('$word','$from_lang','$spelling')");
$word_id=@mysqli_insert_id($db);
}
}
elseif ($line{0} === '*'){
//echo "<br /> slovni druh: $text";
$type='sldruh';
insertni($text,$type,$word_id,$db);
}
elseif ($line{0} === '!'){//fraze
$type='fraze';
//echo "<br /> fraze: $text";
insertni($text,$type,$word_id,$db);
}
elseif ($line{0} === '-'){
$type='vyznam';
//echo "<br /> vyznam: $text";
insertni($text,$type,$word_id,$db);
}
elseif ($line{0} === '='){
$type='vysvetleni';
$rozdel_vyznam=explode("+",$text);
if(!isset($rozdel_vyznam[1])){//kdyz neni vyslovnost
$add='';
}else{
$add=trim($rozdel_vyznam[1]);
$text=trim($rozdel_vyznam[0]);
}
//echo "<br /> dalsi vyznam: $text";
insertni($text,$type,$word_id,$db,$add);
}
}
//}//konec line nr
}
?>Zaimalo by me radek s "//if($line_nr>185642){" Skript skoci primo na ten radek, nebo projde znovu od jednicky? Rozdelit tedy velky soubor na mensi tim, ze nastavim radky nebo cely soubor najednou a zvetsit akorat exec time? |
||
| Alphard Profil |
#7 · Zasláno: 30. 3. 2013, 17:17:03
Nepřejde hned na daný řádek (což by v tomto případě nebyl problém zařídit), ale vynechá zpracování, takže menší hodnoty "procyklí" řádově rychleji.
|
||
| unlucky Profil |
#8 · Zasláno: 30. 3. 2013, 17:22:09
ajo, blba otazka..je tam foreach. Kazdopadne 500tis radku, zpracovat cely soubor ci nejak zmensit?
|
||
| Alphard Profil |
#9 · Zasláno: 30. 3. 2013, 17:25:45
Tohle je jednorázové zpracování doma? Zkusil bych pro pár řádků, jestli to funguje, a pokud ano, tak to pustil a čekal. Proč si přidávat práci zmenšováním souboru...
|
||
| unlucky Profil |
Pustil jsem skript, ktery ma ukladat data ze souboru do databaze. Soubor ma 500 000 radku. Na netbooku (1.6ghz, 512 ram) se mi podarilo za 3000sek dojit az k 1/3. Na PC (nejakych dual 2.4 2mbram). Vse mam stejne nastavene a stejny skript.
Nyni uz je to 20minut a jsem teprve na radku 7500. Jak toto cele urychlit? |
||
| DJ Miky Profil |
#11 · Zasláno: 30. 3. 2013, 21:08:01
To se dá jen hádat, když k tomu není více informací. Osobně bych si tipnul, že ti to na PC brzdí disk, přičemž v netbooku máš rychlejší SSD.
Obecně to můžeš zrychlit třeba neposíláním insertů do databáze po jednom, ale posílání více řádků naráz v jednom insertu ( INSERT INTO ... VALUES (...), (...), (...);). Tím se zmenší počet přepínání kontextu a overhead v podobě řízení transakcí v databázi (každý samostatně vložený řádek spustí transakci, vloží data a commitne transakci).
|
||
| Tori Profil |
Dá se napsat lepší algoritmus. Neprovádíte žádné složité operace s daty, takže nejpomalejší část jsou zřejmě dotazy do DB. Dá se snížit jejich počet mnoha způsoby - jednak viz [#11]. Potom místo dohledávání ID ke každému slovu (ř.43) můžete prostě každé slovo, které vkládáte do DB, zároveň hodit do pole (slovo => id) a místo SELECT dohledávat fcí isset.
Taky se dají nejdřív poukládat všechna data do tabulky word a ostatní si odkládat do jiného pole pod word_id. Po uložení všech jednotlivých slov potom z toho druhého pole (významů) poskládáte hromadné inserty, třeba po 50 - 100 záznamech. V tom případě by bylo potřeba místo file načítat datový soubor přes fgets, ať se nezahlcuje paměť. |
||
| unlucky Profil |
Napada me akorat, ze na netbooku mam windows 7 a na PC, sice novejsi/rychlejsi/lepsi, ale stary XP
Jenom pro porovnani, NTB zpracuje 10 000 radku za 3 min, na PC hodina |
||
| Alphard Profil |
#14 · Zasláno: 31. 3. 2013, 00:30:15
Jestli se v tom chcete vrtat a hledat příčinu, začal bych měřením času, jak dlouho trvají dotazy do databáze.
Pokud jde čistě o optimalizaci, viz kolegové výše. |
||
|
Časová prodleva: 13 let
|
|||
0