整個2015年從開始到結尾都在進行網站向雲服務器的搬遷以及網站的升級,其中大數據量的數據遷移是個令人很頭痛的問題,幾百萬的數據量加上幾十個字段,系列網站還有幾十個這樣的網站,需要等待數據遷移程序運行的時間真是太長太長了。上半年就遇到大數據量的問題,後來通過修改服務器配置,讓PHP使用更多的内存、最大執行時間、數據庫連接緩存等辦法,還是用drush content-migrate-fields這樣的命令來進行,算是解決了部分難以遷移的站點。但現在到年尾,而且随着Drupal 8的退出,Drupal 6很快就面臨失去支持的境況,我們需要把所有Drupal 6網站都升級,現在把所有服務器資源都利用起來,還專門購買16核64G内存的雲服務器臨時實例來加快遷移程序的運行,但按目前的做法算下來,依然是不知道還需要幾個月才能完成。😢
最早寫博文《大數據量Drupal_6網站升級到Drupal_7很麻煩》的時候,采用了數據庫命令來升級的辦法,這無疑是最快的,但因為其它系列站數據結構複雜、數據導入及删除等情況也複雜,所以沒有敢這樣做。再後來一想,drush命令其實很好,但卻N個字段逐個字段進行遷移,這樣用的時間就是N多倍了,也嘗試過想修改drush命令中涉及到的程序來加快進度,但那個程序還比較複雜,看了半天也沒有看懂,不知道如何下手修改。正好前幾個在搬遷一個數據量不大的英文站時,需要編寫一個PHP程序來進行一些數據的匹配、修改、保存,就想到幹脆自己來編寫程序進行Drupal 6到Drupal 7的數據遷移,經過幾天的編寫、調試和使用,證明這是可行的,本來準備一個程序直接讀取Drupal 6站點數據、馬上寫入Drupal 7站點,但調用API初始化上有些問題,就用了兩個PHP程序,中間使用csv文件來做過渡:
- drupal6-file.php :按内容類型讀取Drupal 6網站中的node數據,保存到csv文件中
- file-drupal7.php :逐行讀取csv文件,保存到Drupal 7網站對應的内容類型中(這一步其實也可以用feeds模塊來進行導入)
drupal6-file.php示範程序源代碼如下:
<?php ini_set("display_errors", "On"); error_reporting(E_ALL | E_STRICT); $_SERVER['HTTP_HOST'] = 'chn.youbianku.com'; $_SERVER['REQUEST_URI'] = '/'; $_SERVER['REMOTE_ADDR'] = '127.0.0.1'; $_SERVER['SCRIPT_NAME'] = '/drupal6-file.php'; $drupal6_path = '/alidata/www/chn.youbianku.com/'; chdir($drupal6_path); require_once './includes/bootstrap.inc'; drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); if (isset($argv[1])) { $file_name = $argv[1]; } else { $file_name = "/root/my_array.csv"; } if (isset($argv[2])) { $offset = $argv[2]; } else { $offset = 0; } if (isset($argv[3])) { $limit = $argv[3]; } else { $limit = 10; } $node_type = "address"; $type = $node_type; print "file_name = $file_name offset = $offset limit = $limit\n"; $fields = content_types($type); //print "fields['fields'] = ".$fields['fields']." \n"; $count=0; //print_r($fields); $fields_array=array(); foreach ( $fields['fields'] as $key => $field ) { $fields_array[]=$key; } //print_r($fields_array); $file = fopen($file_name,"w"); $head_array = $fields_array; array_unshift($head_array,'title'); array_unshift($head_array,'nid'); fputcsv($file,$head_array); print "$count,".implode(",",$head_array)."\n"; //$sql = "SELECT node.title, node.type, node.nid FROM {node} WHERE node.type = '$node_type' LIMIT $list_no OFFSET $offset"; $sql = "SELECT node.nid FROM {node} WHERE node.type = '$node_type' LIMIT $limit OFFSET $offset"; $result = db_query($sql); while ($anode = db_fetch_object($result)) { //print_r ($anode); $nid = $anode->nid; $node=node_load($nid); $node_array = get_object_vars($node); //print_r ($node_array); $line_array=array(); foreach ($fields_array as $field) { $line_array[$field] = $node_array[$field][0]['value']; } array_unshift($line_array,$node->title); array_unshift($line_array,$nid); $count++; print "$count,".implode(",",$line_array)."\n"; fputcsv($file,$line_array); unset($nid,$node,$node_array,$line_array,$field); } fclose($file); print "total count = $count\n"; print "-- end --\n"; ?>
file-drupal7.php示範程序源代碼如下:
<?php ini_set("display_errors", "On"); error_reporting(E_ALL | E_STRICT); $_SERVER['HTTP_HOST'] = 'chn.youbianku.com'; $_SERVER['REMOTE_ADDR'] = '127.0.0.1'; $_SERVER['SCRIPT_NAME'] = '/file-drupal7.php'; $drupal7_path = '/alidata/www/chn.youbianku.com/'; chdir($drupal7_path); define('DRUPAL_ROOT', $drupal7_path); require_once './includes/bootstrap.inc'; drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); if (isset($argv[1])) { $file_name = $argv[1]; } else { print "please provide file_name"; exit; } $file = fopen($file_name,"r"); $count=0; //$line = split(',',$fields_array); //print "line = $line\n"; //array_unshift($fields_array,'title'); //array_unshift($fields_array,'nid'); $fields_array=fgetcsv($file); print "$count,".implode(",",$fields_array)."\n"; array_shift($fields_array); array_shift($fields_array); while(! feof($file)) { $line_array = fgetcsv($file); if ($line_array == FALSE) break; $count++; print "$count,".implode(",",$line_array)."\n"; $nid = array_shift($line_array); $title = array_shift($line_array); $node=node_load($nid); // print_r($node); $node_array = get_object_vars($node); //print_r($node_array); foreach($line_array as $key => $field_value) { $field_name = $fields_array[$key]; $node_array[$field_name]['und'][0]['value'] = $field_value; } $node_new = (object) $node_array; node_save($node_new); unset($nid,$title,$node,$node_array,$line_array,$key,$field_value,$field_name,$node_new); } fclose($file); print "total count = $count\n"; print "-- end --\n"; ?>
對于超大數據量的網站來說,運行以上drupal6-file.php程序也需要很長時間,而且占用内存非常大(幾十萬的數量可能超過10G),可以用一個shell批處理調用php程序,分段來處理。而file-drupal7.php占用内存很少,不過依然需要很長時間運行,主要是等待RDS數據庫服務器的IO。
補充:以上程序經過好些天的運行,證明是可以遷移數百萬數量級頁面的網站,不過對于一些drupal 6中内容為空的字段,用drush content-migrate-fields遷移是不在drupal 7中的字段産生新的紀錄,而用上面的程序還是會産生内容為空格('')的記錄,顯得不必要和占用空間,可以用下面類似的語句來判斷和删除:
DELETE FROM `postcodebase_tx`.`field_data_field_urbcitystate` WHERE `field_urbcitystate_value` = ''; DELETE FROM `postcodebase_tx`.`field_data_field_urbcitystate` WHERE `field_urbcitystate_value` is null;
2016年2月23日補充:上面是從drupal 6讀取字段保存到csv文件,然後再讀取csv文件保存到drupal 7的字段,中間用了一個csv文件作為中轉。這幾天還在做一些其它網站的數據遷移收尾工作,遇到分類字段,就嘗試了不用csv文件過渡,而是在drupal 7中直接讀取數據庫中drupal 6老版本數據表中的字段内容,保存到對應的drupal 7的字段中,這樣更簡單、快捷,程序例子:
<?php ini_set("display_errors", "On"); error_reporting(E_ALL | E_STRICT); $_SERVER['HTTP_HOST'] = 'trade.mingluji.com'; $_SERVER['REMOTE_ADDR'] = '127.0.0.1'; $_SERVER['SCRIPT_NAME'] = '/trade.php'; $drupal7_path = '/alidata/www/drupal_update.mingluji.com/'; chdir($drupal7_path); define('DRUPAL_ROOT', $drupal7_path); require_once './includes/bootstrap.inc'; drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); $count=0; $count_change=0; $count_not_change=0; $count_null=0; if (isset($argv[1])) { $node_type = $argv[1]; } else { print "please provide node_type"; exit; } if (isset($argv[2])) { $offset = $argv[2]; } else { $offset = 0; } if (isset($argv[3])) { $limit = $argv[3]; } else { $limit = 100000; } //$node_type = "gongying"; print "node_type = $node_type, offset = $offset, limit = $limit\n"; $sql = "SELECT node.nid FROM {node} WHERE node.type = '$node_type' LIMIT $limit OFFSET $offset"; $result = db_query($sql); while ($anode = $result->fetch()) { $count++; $node=node_load($anode->nid); //$node=node_load('51254'); $nid=$node->nid; if ($nid == NULL) { print "nid is null\n"; $count_null++; continue; } $sql1 = "SELECT field_area_value FROM content_field_area WHERE nid=$nid"; $result1 = db_query($sql1); $array1 = $result1->fetch(); //print_r($array1); $tid = $array1->field_area_value; $new=$node; if ($tid != NULL && $tid != $new->field_area['und'][0]['tid']) { //print_r($new); $new->field_area['und'][0]['tid']=$tid; node_save($new); $count_change++; } else { $count_not_change++; } print "count=$count, nid=$nid, tid=$tid\n"; } echo "Done!\n"; print "count=$count, count_change=$count_change, count_not_change=$count_not_change, count_null = $count_null\n"; ?>
上面程序已經在需要的網站中運行成功,如果需要修改字段名稱或者是多值字段的話,可以另存為多個程序來執行。
评论