DevVeri.com

Boğulacaksan büyük veride boğul!

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

,

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir