Hive Veritabanları Arası Tablo Taşıma
Merhaba arkadaşlar,
Kısa bir aradan sonra BüyükVeri tarafında yeni bir blog yazımda, sizlere sıkça karşılacaşağımız bir problemin beni uğraştırmasından bahsedeceğim.
Bildiğiniz gibi geliştirme safhasında tablolar yapı olarak sürekli değişime uğrar. Bu sebeple tabloyu yedekleyebilir miyiz şeklinde çok istek alırız. Peki Büyük Veri’de bu nasıl olacak?
BüyükVeri dosya sistemi üzerinde kurulduğu için aslında tabloya ait dosyaları yedeklememiz işimizi çözecektir. Ancak dosya seviyesinde işlem yapmamak ve geliştiricilere bu işi paslamak için HIVE veritabanı üzerinde gerçekleştirebiliriz.
Kullandığım HIVE sürümü 1.1.0 ve tablo yeniden adlandırma komutu aşağıdaki gibi.
Test tablomuzu oluşturalım.
hive> create table rn1 ( id int); hive> insert into rn1 values ( 100); hive> insert into rn1 values ( 200); hive> select * from rn1; hive> alter table rn1 rename to rn2;
Bu komutu default veritabanı altında yolladığınızda tablonuzun yeniden adlandırıldığını göreceksiniz. Ancak default dışındaki veritabanlarınızda bu işlemi yaptığınızda aşağıdaki gibi bir hata almaktayım:
hive> alter table rn2 rename to YENIDB.rn3;
Ancak aşağıdaki hatayı almaktayım.
Your query has the following error(s): Error while processing statement: FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask. Unable to alter table. Unable to access old location hdfs://CLUSTER/user/hive/warehouse/rn2 for table default.rn2
Bu hatada tablonun HDFS ‘deki dosyalarına erişemediğini görüyoruz ancak bu mümkün değil, çünkü hive kullanıcısına yetkiler verilmiş durumda ( aksi halde hiç çalıştıramazdık )
HIVE loglarında bu hatayı da aynı şekilde görüyorum. Aslında bug durumu var ve HIVE-10719 numaralı bug’a rastlıyorum.
Aslında HIVE metastore’da yeniden adlandırdığımız tablonun özelliklerini değiştirirken bu hatayı almışız. HIVE 1.2.1 sürümünde bu hatanın fix edildiğini görüyoruz.
Bir diğer yöntem ise HIVE tablosunu export/import ile taşımak. Bu noktada HIVE dökümantasyonunda aşağıdaki bilgileri bulabilirsiniz.
EXPORT TABLE tablename [PARTITION (part_column="value"[, ...])] TO 'export_target_path' IMPORT [[EXTERNAL] TABLE new_or_original_tablename [PARTITION (part_column="value"[, ...])]] FROM 'source_path' [LOCATION 'import_target_path']
Görebileceğiniz gibi kullanımı kolay şimdi bu komutları deneyelim.
Test tablomuzu oluşturalım:
hive> use YENIDB; hive> create table rn4 (id int); hive> insert into rn4 values (790); hive> insert into rn4 values (1); hive> insert into rn4 values (60); hive> select * from rn4;
Tabloya fiziksel olarak bakarsak,
HOST]~$hadoop fs -ls /YENI_DB_DIZINI/YENIDB/ Found 7 items ... drwxrwx---+ - hive supergroup 0 2016-01-29 16:20 /YENI_DB_DIZINI/YENIDB/rn4 ... [HOST]~$hadoop fs -ls /YENI_DB_DIZINI/YENIDB/rn4 Found 3 items -rwxrwx---+ 3 hive supergroup 4 2016-01-29 16:22 /YENI_DB_DIZINI/YENIDB/rn4/000000_0 -rwxrwx---+ 3 hive supergroup 2 2016-01-29 16:22 /YENI_DB_DIZINI/YENIDB/rn4/000000_0_copy_1 -rwxrwx---+ 3 hive supergroup 3 2016-01-29 16:22 /YENI_DB_DIZINI/YENIDB/rn4/000000_0_copy_2
Şimdi tablomuzu export edelim.
hive> export table rn4 to '/tmp/rn4';
Gördüğümüz gibi tablomuzun metadatası (tanım bilgileri) ve verileri dosyaya çıkmış durumda.
[HOST]~$hadoop fs -ls /tmp/rn4 Found 5 items drwxrwxrwx - hive supergroup 0 2016-01-29 16:22 /tmp/rn4/.hive-staging_hive_2016-01-29_16-22-55_385_6263938611577166589-35 drwxrwxrwx - hive supergroup 0 2016-01-29 16:23 /tmp/rn4/.hive-staging_hive_2016-01-29_16-23-41_894_2004760451112761053-35 drwxrwxrwx - hive supergroup 0 2016-01-29 16:24 /tmp/rn4/.hive-staging_hive_2016-01-29_16-24-51_981_2863671248049702467-35 -rwxrwxrwx 3 hive supergroup 1165 2016-01-29 16:22 /tmp/rn4/_metadata drwxrwxrwx - hive supergroup 0 2016-01-29 16:22 /tmp/rn4/data
_metadata dosyasına bakarsak, tablo tanım bilgilerinin olduğunu görürüz.
[HOST]~$hadoop fs -cat /tmp/rn4/_metadata {"version":"0.1","table":"{\"1\":{\"str\":\"rn4\"},\"2\":{\"str\":\"YENIDB\"},\"3\":{\"str\":\"hive\"},\"4\":{\"i32\":1454077197},\"5\":{\"i32\":0},\"6\":{\"i32\":0},\"7\":{\"rec\":{\"1\":{\"lst\":[\"rec\",1,{\"1\":{\"str\":\"id\"},\"2\":{\"str\":\"int\"}}]},\"2\":{\"str\":\"hdfs://CLUSTER/YENI_DB_DIZINI/YENIDB/rn4\"},\"3\":{\"str\":\"org.apache.hadoop.mapred.TextInputFormat\"},\"4\":{\"str\":\"org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat\"},\"5\":{\"tf\":0},\"6\":{\"i32\":-1},\"7\":{\"rec\":{\"2\":{\"str\":\"org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe\"},\"3\":{\"map\":[\"str\",\"str\",1,{\"serialization.format\":\"1\"}]}}},\"8\":{\"lst\":[\"str\",0]},\"9\":{\"lst\":[\"rec\",0]},\"10\":{\"map\":[\"str\",\"str\",0,{}]},\"11\":{\"rec\":{\"1\":{\"lst\":[\"str\",0]},\"2\":{\"lst\":[\"lst\",0]},\"3\":{\"map\":[\"lst\",\"str\",0,{}]}}},\"12\":{\"tf\":0}}},\"8\":{\"lst\":[\"rec\",0]},\"9\":{\"map\":[\"str\",\"str\",6,{\"totalSize\":\"9\",\"numRows\":\"3\",\"rawDataSize\":\"6\",\"COLUMN_STATS_ACCURATE\":\"true\",\"numFiles\":\"3\",\"transient_lastDdlTime\":\"1454077242\"}]},\"12\":{\"str\":\"MANAGED_TABLE\"}}","partitions":[]}[HOST]~$
Tabloyu taşıma adımı:
hive> import table rn42 from '/tmp/rn4';
import komutunu çalıştırtıktan sonra tablomuzun taşındığını görebiliriz.
[HOST]~$hadoop fs -ls /YENI_DB_DIZINI/YENIDB/ Found 7 items ... drwxrwx---+ - hive supergroup 0 2016-01-29 16:20 /YENI_DB_DIZINI/YENIDB/rn4 drwxrwx---+ - hive supergroup 0 2016-01-29 16:22 /YENI_DB_DIZINI/YENIDB/rn42
Şimdi farklı veritabanları arası taşımayı deneyelim, zaten bir önceki adımda burada tıkanmıştı.
hive> import table BASKADB.rn43 from '/tmp/rn4'; INFO : Copying file: hdfs://CLUSTER/tmp/rn4/data/000000_0_copy_1 INFO : Copying file: hdfs://CLUSTER/tmp/rn4/data/000000_0_copy_2 INFO : Loading data to table YENIDB.BASKADB.rn43 from hdfs://CLUSTER/tmp/rn4/.hive-staging_hive_2016-01-29_16-23-41_894_2004760451112761053-35/-ext-10000 ERROR : Failed with exception Invalid table name YENIDB.BASKADB.rn43 org.apache.hadoop.hive.ql.parse.SemanticException: Invalid table name YENIDB.BASKADB.rn43 at org.apache.hadoop.hive.ql.exec.Utilities.getDbTableName(Utilities.java:2321) at org.apache.hadoop.hive.ql.exec.Utilities.getDbTableName(Utilities.java:2307) at org.apache.hadoop.hive.ql.metadata.Hive.getTable(Hive.java:1031) at org.apache.hadoop.hive.ql.metadata.Hive.getTable(Hive.java:1019) at org.apache.hadoop.hive.ql.exec.MoveTask.execute(MoveTask.java:259) at org.apache.hadoop.hive.ql.exec.Task.executeTask(Task.java:160) at org.apache.hadoop.hive.ql.exec.TaskRunner.runSequential(TaskRunner.java:88) at org.apache.hadoop.hive.ql.Driver.launchTask(Driver.java:1638) at org.apache.hadoop.hive.ql.Driver.execute(Driver.java:1397) at org.apache.hadoop.hive.ql.Driver.runInternal(Driver.java:1181) at org.apache.hadoop.hive.ql.Driver.run(Driver.java:1047) at org.apache.hadoop.hive.ql.Driver.run(Driver.java:1042) at org.apache.hive.service.cli.operation.SQLOperation.runQuery(SQLOperation.java:145) at org.apache.hive.service.cli.operation.SQLOperation.access$100(SQLOperation.java:70) at org.apache.hive.service.cli.operation.SQLOperation$1$1.run(SQLOperation.java:197) at java.security.AccessController.doPrivileged(Native Method) at javax.security.auth.Subject.doAs(Subject.java:422) at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1671) at org.apache.hive.service.cli.operation.SQLOperation$1.run(SQLOperation.java:209) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745)
Gördüğünüz gibi buradaki hata basit , HIVE import edilen tablonun başına bağlı olduğumuz veritabanının adını ekliyor.
Çözüm olarak tabloyu aktaracağımız veritabanına bağlanıp, import komutunu çalıştırmamız gerekiyor.
hive> use BASKADB; hive> import table rn43 from '/tmp/rn4';
Evet arkadaşlar, import çalıştı, yeni tabloyu fiziksel olarak test edip verilerimizin var olduğunu doğrulayalım.
[HOST]~$hadoop fs -ls /PATH_TO_BASKADB/BASKADB/rn43 Found 3 items -rwxrwx---+ 3 hive supergroup 4 2016-01-29 16:24 /PATH_TO_BASKADB/BASKADB/rn43/000000_0 -rwxrwx---+ 3 hive supergroup 2 2016-01-29 16:24 /PATH_TO_BASKADB/BASKADB/rn43000000_0_copy_1 -rwxrwx---+ 3 hive supergroup 3 2016-01-29 16:24 /PATH_TO_BASKADB/BASKADB/rn43/000000_0_copy_2
Sorun gözükmüyor. Bu çalışma ile aslında sık yaptığımız tablo yedekleme/yeniden adlandırma işlerinde aldığımız hataları çözdük arkadaşlar.
Export/import yöntemi dosya seviyesinde kopyalama yaptığı için çok hızlı, aslında hive rename komutu da aynı işi yapmakta ancak 1.1.0 sürümünde hata alınmakta. Bir diğer tablo taşıma yöntemi de CTAS yöntemi, yani yeni tabloyu oluşturup insert komutu ile veriyi taşımak.
Metadata export/import yöntemi ile taşıyacağınız tablonun yapısı ile ilgili bilgi sahibi olmanıza gerek olmadığı için tavsiye ettiğim bir çözüm.
Evet arkadaşlar, yazımız burda sonlanıyor. Umarım faydalı bir çalışma olmuştur.
İyi çalışmalar.
Kaynak:
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+ImportExport
https://issues.apache.org/jira/browse/HIVE-10719
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-RenameTable
Basit Lineer Regresyon Big Data Teknolojilerine Hızlı Giriş