Я пытаюсь проанализировать массивный XML-файл в моей базе данных MySQL. файл равен 4.7gb. Я знаю, его безумный.
Данные поступают отсюда: http://www.discogs.com/data/ (самый новый альбом xml – 700mb zipped и 4.7gb unzipped)
Я могу использовать java или php для анализа и обновления базы данных. Я предполагаю, что java – это более умная идея.
Мне нужно найти способ разобрать xml без заполнения моего 4gb бара и загрузить его в db.
Каков самый умный способ сделать это? Я слышал о парсерах SAX, я думаю в правильном направлении?
На данный момент, я не забочусь о загрузке изображений с этих URL-адресов, мне просто нужны данные в моей базе данных. Я еще не разработал таблицы, но сейчас меня больше интересует xml-сторона.
Я использовал php's fread (), чтобы открыть первые 1000 укусов файла, поэтому, по крайней мере, я могу видеть, как он выглядит, вот образец структуры первого альбома в файле:
<releases> <release id="1" status="Accepted"> <images> <image height="600" type="primary" uri="http://s.dsimg.com/image/R-1-1193812031.jpeg" uri150="http://s.dsimg.com/image/R-150-1-1193812031.jpeg" width="600" /> <image height="600" type="secondary" uri="http://s.dsimg.com/image/R-1-1193812053.jpeg" uri150="http://s.dsimg.com/image/R-150-1-1193812053.jpeg" width="600" /> <image height="600" type="secondary" uri="http://s.dsimg.com/image/R-1-1193812072.jpeg" uri150="http://s.dsimg.com/image/R-150-1-1193812072.jpeg" width="600" /> <image height="600" type="secondary" uri="http://s.dsimg.com/image/R-1-1193812091.jpeg" uri150="http://s.dsimg.com/image/R-150-1-1193812091.jpeg" width="600" /> </images> <artists> <artist> <name>Persuader, The</name> </artist> </artists> <title>Stockholm</title> <labels> <label catno="SK032" name="Svek" /> </labels> <formats> <format name="Vinyl" qty="2"> <descriptions> <description>12"</description> </descriptions> </format> </formats> <genres> <genre>Electronic</genre> </genres> <styles> <style>Deep House</style> </styles> <country>Sweden</country> <released>1999-03-00</released> <notes>Recorded at the Globe studio in Stockholm. The titles are the names of Stockholm's districts.</notes> <master_id>5427</master_id> <tracklist> <track> <position>A</position> <title>Östermalm</title> <duration>4:45</duration> </track> <track> <position>B1</position> <title>Vasastaden</title> <duration>6:11</duration> </track> <track> <position>B2</position> <title>Kungsholmen</title> <duration>2:49</duration> </track> <track> <position>C1</position> <title>Södermalm</title> <duration>5:38</duration> </track> <track> <position>C2</position> <title>Norrmalm</title> <duration>4:52</duration> </track> <track> <position>D</position> <title>Gamla Stan</title> <duration>5:16</duration> </track> </tracklist> </release>
Благодарю.
Я столкнулся с подобной проблемой. Вот часть скрипта, импортированного около 28 МБ файла, не считывая целые данные в память. Это должно сработать возможно :). Он читает его узлами XML, в памяти остается лишь небольшая часть XML. Скрипт будет нуждаться в небольших модификациях в соответствии с вашими потребностями.
$reader = new XMLReader(); $reader->open(<path_to_large_xml_file>); while ($reader->read()) { switch ($reader->nodeType) { case (XMLREADER::ELEMENT): if ($reader->localName == "Table") { $node = $reader->expand(); $dom = new DomDocument(); $n = $dom->importNode($node,true); $dom->appendChild($n); $sxe = simplexml_import_dom($n); $Data = array(); $DataColumns = array(); foreach ($columns as $key => $column) { if (in_array($key,$DateColumns)) { $DateArray = explode('/',substr(trim($sxe->$column),0,10)); $ValueColumn = date('Ymd H:i:s',mktime(0,0,0,$DateArray[1],$DateArray[0],$DateArray[2])); $Data[] = '\''.$ValueColumn.'\''; $DataColumns[] = $key; if ($SplitDateInsert == 'enabled') { $Data[] = '\''.$DateArray[2].'\''; $Data[] = '\''.$DateArray[1].'\''; $Data[] = '\''.$DateArray[0].'\''; $DataColumns[] = $key.'_year'; $DataColumns[] = $key.'_month'; $DataColumns[] = $key.'_day'; } } else { $ValueColumn = addslashes(trim($sxe->$column)); $Data[] = '\''.$ValueColumn.'\''; $DataColumns[] = $key; } } $SQL = "INSERT INTO {$tableName} (".implode(',',$DataColumns).") VALUES (".implode(',',$Data).")"; $db->query($SQL); } // END IF table } }
Вам, очевидно, нужен потоковый API, а не DOM, который должен содержать весь документ в памяти. Java поддерживает SAX и Stax . Я никогда не использовал Stax, но слышал, что его проще использовать, чем SAX, хотя он все же эффективен.
Не забудьте также разделить работу на многие транзакции: база данных не сможет поддерживать столько операторов вставки в одной транзакции.
Если я буду разбирать его с помощью PHP, я бы сделал это в два этапа:
<release>
и сделайте этот мини-файл допустимым XML. Если скорость не является существенной, то PHP действительно будет лучше, так как легко анализировать тексты / XML в PHP.
Предполагая, что MySQL имеет аналогичные возможности, такие как Oracle, в этом отношении, почему бы не позволить БД обрабатывать разбор? В oracle вы можете просто зарегистрировать XMLSchema, создать структурированную таблицу XMLType (возможно, более полезную, чем clob), а затем вставить файл.
Никогда не использовал его для чего-то такого большого, но я не понимаю, почему он не должен работать, и это делается в нескольких строках кода. Чтобы узнать, как работают детали, вам нужен только кто-то, у кого есть опыт работы с MySQL.
Я бы предпочел использовать Stax на Java. Или, даже проще, StaxMate, который добавляет немного больше удобства для доступа.
Но что именно вам нужно делать с XML? Чтобы просто потопить его в БД, есть способы обрабатывать BLOB как потоки (хотя mySQL JDBC-драйверы известны своими причудами), так что это должно быть выполнимо.
4.7 ГБ не безумный, просто мягкий. Если у вас 64-разрядная Java, расширенный VTD-XML должен быть наиболее эффективным и простым в использовании вариантом.
Вы не сказали, какую обработку вы хотите делать с XML. Вы можете рассмотреть использование XSLT в потоковом режиме Saxon (для этого нужен продукт Saxon-EE, который стоит денег) – если обработка по существу является «потоковым» потоковым выполнением обработки каждого элемента «выпуска» по очереди, t быть слишком сложным. Конечно, вы также можете использовать низкоуровневый синтаксический анализ SAX или StaX, но это почти наверняка потребует разработки и отладки большего количества кода.