Hadoop分佈式文件系統使用指南
- 文件權限和授權。
- 機架感知(Rack awareness):在調度任務和分配存儲空間時考慮節點的物理位置。
- 安全模式:一種維護需要的管理模式。
- fsck:一個診斷文件系統健康狀況的工具,能夠發現丟失的文件或數據塊。
- Rebalancer:當datanode之間數據不均衡時,平衡集群上的數據負載。
- 升級和回滾:在軟件更新後有異常發生的情形下,能夠回滾到HDFS升級之前的狀態。
- Secondary Namenode:對文件系統名字空間執行週期性的檢查點,將Namenode上HDFS改動日誌文件的大小控制在某個特定的限度下。
DFSAdmin 命令
-report
報告HDFS的基本統計信息。有些信息也可以在NameNode Web服務首頁看到
$ bin/hadoop dfsadmin -report
- 執行畫面
Total raw bytes: 59529687040 (55.44 GB) Remaining raw bytes: 46887116647 (43.67 GB) Used raw bytes: 24576 (24 KB) % used: 0% Total effective bytes: 0 (0 KB) Effective replication multiplier: Infinity ------------------------------------------------- Datanodes available: 1 Name: 140.110.141.129:50010 State : In Service Total raw bytes: 59529687040 (55.44 GB) Remaining raw bytes: 46887116647(43.67 GB) Used raw bytes: 24576 (24 KB) % used: 0% Last contact: Wed Apr 01 14:49:39 CST 2009
-safemode
雖然通常並不需要,但是管理員的確可以手動讓NameNode進入或離開安全模式。
$ bin/hadoop dfsadmin -safemode Usage: java DFSAdmin [-safemode enter | leave | get | wait]
$ bin/hadoop dfsadmin -safemode enter Safe mode is ON $ bin/hadoop dfsadmin -safemode leave Safe mode is OFF
安全模式的作用
- NameNode啟動時會從fsimage和edits日誌文件中裝載文件系統的狀態信息,接著它等待各個DataNode向它報告它們各自的數據塊狀態,這樣,NameNode就不會過早地開始複製數據塊,即使在副本充足的情況下。
- 這個階段,NameNode處於安全模式下。NameNode的安全模式本質上是HDFS集群的一種只讀模式,此時集群不允許任何對文件系統或者數據塊修改的操作。通常NameNode會在開始階段自動地退出安全模式。
- 如果需要,你也可以通過'bin/hadoop dfsadmin -safemode'命令顯式地將HDFS置於安全模式。NameNode首頁會顯示當前是否處於安全模式。關於安全模式的更多介紹和配置信息請參考JavaDoc:setSafeMode()。
-finalizeUpgrade
刪除上一次升級時製作的集群備份
Secondary NameNode
- Secondary NameNode定期合併fsimage和edits日誌,將edits日誌文件大小控制在一個限度下。因為內存需求和NameNode在一個數量級上,所以通常secondary NameNode和NameNode運行在不同的機器上。
- Secondary NameNode由bin/start-dfs.sh在conf/masters中指定的節點上啟動
- conf/masters的作用為:指定secondarynamenode,此檔內可寫入多個ip,則有多個第二名稱節點。(已由ip被寫入此檔的節點都會有第二名稱節點日誌而得到驗證)
$ bin/hadoop-daemon.sh --config ./conf start secondarynamenode starting secondarynamenode, logging to /tmp/hadoop/logs/hadoop-waue-secondarynamenode-Dx7200.out
動態加入datanode 與 tasktracker
- 是否能連到正確的namenode取決於conf/hadoop-site.xml,目前測試結果與conf/slave、masters無關
$ bin/hadoop-daemon.sh --config ./conf start datanode starting datanode, logging to /tmp/hadoop/logs/hadoop-waue-datanode-Dx7200.out
$ bin/hadoop-daemon.sh --config ./conf start tasktracker starting tasktracker, logging to /tmp/hadoop/logs/hadoop-waue-tasktracker-Dx7200.out
balancer
用於分析數據塊分佈和重新平衡DataNode上的數據分佈
$ bin/hadoop balancer Time Stamp Iteration# Bytes Already Moved Bytes Left To Move Bytes Being Moved 09/04/01 18:00:08 INFO net.NetworkTopology: Adding a new node: /default-rack/140.110.138.191:50010 09/04/01 18:00:08 INFO net.NetworkTopology: Adding a new node: /default-rack/140.110.141.129:50010 09/04/01 18:00:08 INFO dfs.Balancer: 0 over utilized nodes: 09/04/01 18:00:08 INFO dfs.Balancer: 0 under utilized nodes: The cluster is balanced. Exiting... Balancing took 186.0 milliseconds
機架感知(Rack awareness)
據說是設定某個參數 dfs.network.script ,旦目前為止還是不知道這個參數在哪
References
- http://www.michael-noll.com/wiki/Running_Hadoop_On_Ubuntu_Linux_(Multi-Node_Cluster)
- http://cn.hadoop.org/doc/hdfs_user_guide.html
Hadoop分佈式文件系統使用指南二
升級
- 由於換版本的話,資料夾內的conf設定檔也勢必被更改,因此目前作法為: 把conf 移至/opt/conf ,hadoop 0.16 與 hadoop 0.18用 ln 做捷徑代換。由於conf已不在hadoop_home內,因此記得匯入conf/hadoop-env.sh
$ source /opt/conf/hadoop-env.sh
- 先看狀態
$ bin/hadoop dfsadmin -upgradeProgress status There are no upgrades in progress.
- 停止hdfs
- 注意不可使用bin/stop-all.sh來停止
$ bin/stop-dfs.sh
- 注意不可使用bin/stop-all.sh來停止
- 部署新版本的Hadoop
- 注意每個node的版本都要統一,否則會出現問題
- 啟動
$ bin/start-dfs.sh -upgrade
ps:之後有介紹到 bin/hadoop namenode -upgrade ,應該要查查看與 $ bin/start-dfs.sh -upgrade 有何不同
- namenode管理網頁會出現升級狀態
退回
- 停止集群
$ bin/stop-dfs.sh
- 部署老版本的Hadoop
- 退回之前版本
$ bin/start-dfs.sh -rollback
ps:之後有介紹到 bin/hadoop namenode -rollback ,應該要查查看與 $ bin/start-dfs.sh -rollback 有何不同
bin/hadoop 的使用者用法
$ hadoop [--config confdir] [COMMAND] [GENERIC_OPTIONS] [COMMAND_OPTIONS]
[GENERIC_OPTIONS] :
-conf <configuration file> 指定應用程序的配置文件。 -D <property=value> 為指定property指定值value。 -fs <local|namenode:port> 指定namenode。 -jt <local|jobtracker:port> 指定job tracker。只適用於job。
archieve
- archieve就是把資料壓縮成一個檔案,在壓縮的過程中,還會將被壓縮的目錄結構紀錄在index與masterindex內。
- 由於每個上傳上去的檔案都被放在一個block中,因此我的input資料夾內共有四個檔,但是每個檔都會佔用一個block,用此方法就可以按照整個打包大小來分配共用去多少個block數。
- hadoop archive -archiveName name <src>* <dest>
$ bin/hadoop archive -archiveName foo.har input/* output 09/04/02 14:02:30 WARN mapred.JobClient: Use GenericOptionsParser for parsing the arguments. Applications should implement Tool for the same. 09/04/02 14:02:30 INFO mapred.JobClient: Running job: job_200904021140_0001 09/04/02 14:02:31 INFO mapred.JobClient: map 0% reduce 0% 09/04/02 14:02:44 INFO mapred.JobClient: map 20% reduce 0% 09/04/02 14:02:49 INFO mapred.JobClient: map 100% reduce 0% 09/04/02 14:02:56 INFO mapred.JobClient: Job complete: job_200904021140_0001 ...略
- 看har裡面的檔案結構
$ bin/hadoop dfs -lsr /user/waue/output/foo.har
- 看har內檔案的內容
$ bin/hadoop dfs -cat /user/waue/output/foo.har/part-0
- ps: 官方文件介紹的 hadoop dfs -lsr har:///user/hadoop/output/foo.har 會出現錯誤!
lsr: could not get get listing for 'har:/user/waue/output/foo.har/user/waue' : File: har://hdfs-gm1.nchc.org.tw:9000/user/waue/output/foo.har/user/waue/input does not exist in har:///user/waue/output/foo.har
distCp
- 是用於大規模集群內部和集群之間拷貝的工具
- 使用Map/Reduce實現文件分發,錯誤處理和恢復,以及報告生成
- 舉例為:
hadoop distcp hdfs://nn1:8020/foo/bar hdfs://nn2:8020/bar/foo
?? 然而8020 port 在機器上沒有開,且不是應該檔案會均勻散佈在每個節點上嗎?怎麼還會知道nn1的節點上有這個檔要複製到nn2呢?
fsck
- HDFS文件系統檢查工具
$ bin/hadoop fsck / . /user/waue/input/1.txt: Under replicated blk_-90085106852013388_1001. Target Replicas is 3 but found 2 replica(s). /user/waue/input/1.txt: Under replicated blk_-4027196261436469955_1001. Target Replicas is 3 but found 2 replica(s). . /user/waue/input/2.txt: Under replicated blk_-2300843106107816641_1002. Target Replicas is 3 but found 2 replica(s). . /user/waue/input/3.txt: Under replicated blk_-1561577350198661966_1003. Target Replicas is 3 but found 2 replica(s). . /user/waue/input/4.txt: Under replicated blk_1316726598778579026_1004. Target Replicas is 3 but found 2 replica(s). Status: HEALTHY Total size: 143451003 B Total dirs: 8 Total files: 4 Total blocks (validated): 5 (avg. block size 28690200 B) Minimally replicated blocks: 5 (100.0 %) Over-replicated blocks: 0 (0.0 %) Under-replicated blocks: 5 (100.0 %) Mis-replicated blocks: 0 (0.0 %) Default replication factor: 3 Average block replication: 2.0 Corrupt blocks: 0 Missing replicas: 5 (50.0 %) Number of data-nodes: 2 Number of racks: 1 The filesystem under path '/' is HEALTHY
- 加不同的參數有不同的用處,如
$ bin/hadoop fsck / -files /tmp <dir> /tmp/hadoop <dir> /tmp/hadoop/hadoop-waue <dir> /tmp/hadoop/hadoop-waue/mapred <dir> /tmp/hadoop/hadoop-waue/mapred/system <dir> /user <dir> /user/waue <dir> /user/waue/input <dir> /user/waue/input/1.txt 115045564 bytes, 2 block(s): Under replicated blk_-90085106852013388_1001. Target Replicas is 3 but found 2 replica(s). Under replicated blk_-4027196261436469955_1001. Target Replicas is 3 but found 2 replica(s). /user/waue/input/2.txt 987864 bytes, 1 block(s): Under replicated blk_-2300843106107816641_1002. Target Replicas is 3 but found 2 replica(s). /user/waue/input/3.txt 1573048 bytes, 1 block(s): Under replicated blk_-1561577350198661966_1003. Target Replicas is 3 but found 2 replica(s). /user/waue/input/4.txt 25844527 bytes, 1 block(s): Under replicated blk_1316726598778579026_1004. Target Replicas is 3 but found 2 replica(s). Status: HEALTHY ....(同上)
-move -delete -openforwrite 移動受損文件到/lost+found 刪除受損文件 印出寫打開的文件
-files -blocks -locations -racks 印出正被檢查的文件 印出區塊的資訊 印出每個區塊的位置 印出data-node的網絡拓撲結構
如:
$ bin/hadoop fsck /user/waue/input/1.txt -files -blocks -locations /user/waue/input/1.txt 115045564 bytes, 2 block(s): Under replicated blk_-90085106852013388_1001. Target Replicas is 3 but found 2 replica(s). Under replicated blk_-4027196261436469955_1001. Target Replicas is 3 but found 2 replica(s). 0. blk_-90085106852013388_1001 len=67108864 repl=2 [140.110.138.191:50010, 140.110.141.129:50010] 1. blk_-4027196261436469955_1001 len=47936700 repl=2 [140.110.138.191:50010, 140.110.141.129:50010] Status: HEALTHY Total size: 115045564 B Total dirs: 0 Total files: 1 ....(略)
job
- 用以跟Map Reduce 的作業程序溝通
- 在測試此指令之前,請確認已經先執行過mapReduce的程序過
- 可到JobTracker:50030網頁來看程序的Jobid
-status
- 查看工作狀態
$ bin/hadoop job -status job_200904021140_0001
-kill
- 終止正在執行的程序,其id為 job_200904021140_0001
$ bin/hadoop job -kill job_200904021140_0001
-list
- 印出所有程序的狀態
$ bin/hadoop job -list all 5 jobs submitted States are: Running : 1 Succeded : 2 Failed : 3 Prep : 4 JobId State StartTime UserName job_200904021140_0001 2 1238652150499 waue job_200904021140_0002 3 1238657754096 waue job_200904021140_0004 3 1238657989495 waue job_200904021140_0005 2 1238658076347 waue job_200904021140_0006 2 1238658644666 waue
-history
- 印出程序的歷史狀態
$ bin/hadoop job -history /user/waue/stream-output1 Hadoop job: job_200904021140_0005 ===================================== Job tracker host name: gm1.nchc.org.tw job tracker start time: Thu Apr 02 11:40:06 CST 2009 User: waue JobName: streamjob9019.jar JobConf: hdfs://gm1.nchc.org.tw:9000/tmp/hadoop/hadoop-waue/mapred/system/job_200904021140_0005/job.xml Submitted At: 2-四月-2009 15:41:16 Launched At: 2-四月-2009 15:41:16 (0sec) Finished At: 2-四月-2009 15:42:04 (48sec) Status: SUCCESS ===================================== ...略
version
- 印出目前的hadoop 版本
bin/hadoop version Hadoop 0.18.3 Subversion https://svn.apache.org/repos/asf/hadoop/core/branches/branch-0.18 -r 736250 Compiled by ndaley on Thu Jan 22 23:12:08 UTC 2009
bin/hadoop 的管理者用法
balancer
- 用來讓hdfs的資料能均勻分散
$ bin/hadoop balancer
daemonlog
- 不太知道用法??
$ bin/hadoop daemonlog -getlevel gm1.nchc.org.tw:50070 dfshealth.jsp Connecting to http://gm1.nchc.org.tw:50070/logLevel?log=dfshealth.jsp Submitted Log Name: dfshealth.jsp Log Class: org.apache.commons.logging.impl.Log4JLogger Effective level: INFO
dfsadmin
-report
- 呈現報告
$ bin/hadoop dfsadmin -report
-safemode
enter leave get wait $ bin/hadoop dfsadmin enter $ bin/hadoop dfsadmin -safemode leave
-refreshNodes
- 更新Namenode 需要退出或加入的Datanode 的清單
$ bin/hadoop dfsadmin -refreshNodes
-finalizeUpgrade
- 終結升級程序
-upgradeProgress
status details force 升級狀態 狀態的細節 強制升級操作進行
-setQuota
- 目錄配額是對目錄樹上該目錄下的名字數量做硬性限制
- 設定配額,數字代表個數 (如:我上傳了一個2個block的檔案可以上傳,但我上傳兩個檔案很小的檔上去卻不行)
- 配額為1可以強制目錄保持為空
- 重命名不會改變該目錄的配額
$ bin/hadoop dfs -mkdir quota $ bin/hadoop dfsadmin -setQuota 2 quota $ bin/hadoop dfs -put ../conf/hadoop-env.sh quota/ $ bin/hadoop dfs -put ../conf/hadoop-site.xml quota/ put: org.apache.hadoop.dfs.QuotaExceededException: The quota of /user/waue/quota is exceeded: quota=2 count=3
- 檢查目錄的配額方法: "bin/hadoop fs -count -q <目錄> "
$ bin/hadoop fs -count -q own
none inf 1 0 0 hdfs://gm1.nchc.org.tw:9000/user/waue/own
$ bin/hadoop dfsadmin -setQuota 4 own
$ bin/hadoop fs -count -q own
4 3 1 0 0 hdfs://gm1.nchc.org.tw:9000/user/waue/own
-clrQuota
- 清除之前設定的配額
$ bin/hadoop dfsadmin -clrQuota quota/
namenode
- hadoop namenode [-format] | [-upgrade] | [-rollback] | [-finalize] | [-importCheckpoint]
secondarynamenode
- 用法:hadoop secondarynamenode [-checkpoint [force]] | [-geteditsize]
tasktracker、datanode
- 不可直接下 bin/hadoop tasktracker 這個指令,下此指令的節點 tasktracker:50060 網頁會出現錯誤訊息
- 可以搭配 bin/hadoop-daemon.sh --config <hadoop_conf_dir> "start|stop" "datanode|tasktracker" 來新加入或停止節點
Hadoop Streaming 函式庫用法
- Hadoop streaming是Hadoop的一個工具, 它幫助用戶創建和運行一類特殊的map/reduce作業, 這些特殊的map/reduce作業是由一些可執行文件或腳本文件充當mapper或者reducer
- 最簡單的透過shell執行stream的map reduce:
$ bin/hadoop jar hadoop-0.18.3-streaming.jar -input input -output stream-output1 -mapper /bin/cat -reducer /usr/bin/wc
- 輸出的結果為: (代表 行、字數、字元數)
2910628 24507806 143451003
- 輸出的結果為: (代表 行、字數、字元數)
HDFS權限管理用戶
- hdfs的權限有owner, group, other三種
- 而用戶的身份取決於client上的使用者 (用 whoami),群組為(bash -c groups)
- 相關的操作:
$ bin/hadoop dfs -mkdir own $ bin/hadoop dfs -chmod -R 755 own $ bin/hadoop dfs -chgrp -R waue own $ bin/hadoop dfs -chown -R waue own $ bin/hadoop dfs -lsr own
- conf/hadoop-site.xml 可用參數:
dfs.permissions = true dfs.web.ugi = webuser,webgroup dfs.permissions.supergroup = supergroup dfs.upgrade.permission = 777 dfs.umask = 022
HDFS shell 的用法
- bin/hadoop dfs <args> ,下面則列出 <args> 的用法
- 以下操作預設的目錄在 /user/<$username>/ 下
$ bin/hadoop dfs -ls input Found 4 items -rw-r--r-- 2 waue supergroup 115045564 2009-04-02 11:51 /user/waue/input/1.txt -rw-r--r-- 2 waue supergroup 987864 2009-04-02 11:51 /user/waue/input/2.txt -rw-r--r-- 2 waue supergroup 1573048 2009-04-02 11:51 /user/waue/input/3.txt -rw-r--r-- 2 waue supergroup 25844527 2009-04-02 11:51 /user/waue/input/4.txt
- 完整的路徑則是 hdfs://node:port/path 如:
$ bin/hadoop dfs -ls hdfs://gm1.nchc.org.tw:9000/user/waue/input Found 4 items -rw-r--r-- 2 waue supergroup 115045564 2009-04-02 11:51 /user/waue/input/1.txt -rw-r--r-- 2 waue supergroup 987864 2009-04-02 11:51 /user/waue/input/2.txt -rw-r--r-- 2 waue supergroup 1573048 2009-04-02 11:51 /user/waue/input/3.txt -rw-r--r-- 2 waue supergroup 25844527 2009-04-02 11:51 /user/waue/input/4.txt
-cat
- 將路徑指定文件的內容輸出到stdout
$ bin/hadoop dfs -cat quota/hadoop-env.sh
-chgrp
- 改變文件所屬的組
$ bin/hadoop dfs -chgrp -R waue own
-chmod
- 改變文件的權限
$ bin/hadoop dfs -chmod -R 755 own
-chown
- 改變文件的擁有者
$ bin/hadoop dfs -chown -R waue own
-copyFromLocal, -put
- 從local放檔案到hdfs
$ bin/hadoop dfs -put input dfs_input
-copyToLocal, -get
- 把hdfs上得檔案下載到 local
$ bin/hadoop dfs -get dfs_input input1
-cp
- 將文件從hdfs原本路徑複製到hdfs目標路徑
$ bin/hadoop dfs -cp own waue
-du
- 顯示目錄中所有文件的大小
$ bin/hadoop dfs -du input Found 4 items 115045564 hdfs://gm1.nchc.org.tw:9000/user/waue/input/1.txt 987864 hdfs://gm1.nchc.org.tw:9000/user/waue/input/2.txt 1573048 hdfs://gm1.nchc.org.tw:9000/user/waue/input/3.txt 25844527 hdfs://gm1.nchc.org.tw:9000/user/waue/input/4.txt
-dus
- 顯示該目錄/文件的總大小
$ bin/hadoop dfs -dus input hdfs://gm1.nchc.org.tw:9000/user/waue/input 143451003
-expunge
- 清空垃圾桶
$ bin/hadoop fs -expunge
-getmerge
- 將來源目錄<src>下所有的文件都集合到本地端一個<localdst>檔案內
- bin/hadoop fs -getmerge <src> <localdst>
$ echo "this is one; " >> in1/input $ echo "this is two; " >> in1/input2 $ bin/hadoop dfs -put in1 in1 $ bin/hadoop dfs -getmerge in1 merge.txt $ cat ./merge.txt
-ls
- 列出文件或目錄的資訊
- 文件名 <副本數> 文件大小 修改日期 修改時間 權限 用戶ID 組ID
- 目錄名 <dir> 修改日期 修改時間 權限 用戶ID 組ID
$ bin/hadoop dfs -ls
-lsr
- ls命令的遞迴版本
$ bin/hadoop dfs -lsr /
-mkdir
- 建立資料夾
$ bin/hadoop dfs -mkdir a b c
-moveFromLocal
- 將local端的資料夾剪下移動到hdfs上
$ bin/hadoop dfs -moveFromLocal in1 in2
-mv
- 更改資料的名稱
$ bin/hadoop dfs -mv in2 in3
-rm
- 刪除指定的檔案(不可資料夾)
$ bin/hadoop dfs -rm in1/input
-rmr
- 遞迴刪除資料夾(包含在內的所有檔案)
$ bin/hadoop dfs -rmr in1
-setrep
- 設定副本係數
- bin/hadoop fs -setrep [-R] [-w] <rep> <path/file>
$ bin/hadoop fs -setrep -w 2 -R input Replication 2 set: hdfs://gm1.nchc.org.tw:9000/user/waue/input/1.txt Replication 2 set: hdfs://gm1.nchc.org.tw:9000/user/waue/input/2.txt Replication 2 set: hdfs://gm1.nchc.org.tw:9000/user/waue/input/3.txt Replication 2 set: hdfs://gm1.nchc.org.tw:9000/user/waue/input/4.txt Waiting for hdfs://gm1.nchc.org.tw:9000/user/waue/input/1.txt ... done Waiting for hdfs://gm1.nchc.org.tw:9000/user/waue/input/2.txt ... done Waiting for hdfs://gm1.nchc.org.tw:9000/user/waue/input/3.txt ... done Waiting for hdfs://gm1.nchc.org.tw:9000/user/waue/input/4.txt ... done
-stat
- 印出時間資訊
$ bin/hadoop fs -stat input 2009-04-02 03:51:29
-tail
- 將文件的最後1k內容輸出
- 用法 : bin/hadoop fs -tail [-f] 檔案 (-f 參數用來顯示如果檔案增大,則秀出被append上得內容)
$ bin/hadoop dfs -tail input/1.txt
-test
- 測試檔案, -e 檢查文件是否存在(1=存在, 0=否), -z 檢查文件是否為空(1=空, 0=不為空), -d 檢查是否為目錄(1=存在, 0=否)
- 要用echo $? 來看回傳值為 0 or 1
- 用法: bin/hadoop fs -test -[ezd] URI
$ bin/hadoop dfs -test -e /user/waue/input/5.txt $ bin/hadoop dfs -test -z /user/waue/input/5.txt test: File does not exist: /user/waue/input/5.txt $ bin/hadoop dfs -test -d /user/waue/input/5.txt test: File does not exist: /user/waue/input/5.txt
-text
- 將檔案(如壓縮檔, textrecordinputstream)輸出為純文字格式
- hadoop fs -text <src>
$ hadoop dfs -text macadr-eth1.txt.gz 00:1b:fc:61:75:b1 00:1b:fc:58:9c:23
- ps : 目前沒支援zip的函式庫
$ bin/hadoop dfs -text b/a.txt.zip PK ���:��H{ a.txtUT b��Ib��IUx��sssss test PK ���:��H{ ��a.txtUTb��IUxPK@C
-touchz
- 建立一個空文件
$ bin/hadoop dfs -touchz b/kk $ bin/hadoop dfs -test -z b/kk $ echo $? 1 $ bin/hadoop dfs -test -z b/a.txt.zip $ echo $? 0
Nutch 安裝測試
前言
- 之前有安裝過nutch (version 0.9)並成功運作於四台主機上。由於想到之後上課可能有需要,再重新操作一次
- 網址 : nutch
- 這次的測試與之前的測試不同點在於:
- 版本更新 nutch from 0.9 -> 1.0, tomcat 5.5 -> 6.0
- 之前是空的環境下直接安裝nutch,也沒有hadoop的基礎來安裝,因此目錄結構都用nutch官網介紹的;然而這次的安裝測試在於把nutch運行在已經有的hadoop之上。不過測試的結果是失敗了,錯誤訊息在於找不到dfs之類的訊息。
- 於是又再退回最原始的方法,用空的環境架nutch,並且所有的安裝都用最簡單的設定,步驟如下:
step 1 登入免密碼
- 這是最基本的,怎麼做就不贅述。
step 2 下載與安裝
- 下載 java 1.6
$ sudo apt-get install sun-java6-bin
- 下載 nutch 1.0 (2009/03/28)
$ wget http://ftp.twaren.net/Unix/Web/apache/lucene/nutch/nutch-1.0.tar.gz
step 3 編輯設定檔
- 所有的設定檔都在 $NUTCH_HOME/conf 下
3.1 hadoop-env.sh
將原本的檔案hadoop-env.sh任意處插入
export JAVA_HOME=/usr/lib/jvm/java-6-sun export HADOOP_HOME=/opt/nutch export HADOOP_LOG_DIR=/tmp/nutch/logs export HADOOP_SLAVES=/opt/nutch/conf/slaves
3.2 hadoop-site.xml
<configuration>
<property>
<name>fs.default.name</name>
<value>gm1.nchc.org.tw:9000</value>
<description> The name of the default file system. Either the literal string "local" or a host:port for NDFS. </description>
</property>
<property>
<name>mapred.job.tracker</name>
<value>gm1.nchc.org.tw:9001</value>
<description> The host and port that the MapReduce job tracker runs at. If "local", then jobs are run in-process as a single map and reduce task. </description>
</property>
</configuration>
3.3 nutch-site.xml
<configuration>
<property>
<name>http.agent.name</name>
<value>waue</value>
<description>HTTP 'User-Agent' request header. </description>
</property>
<property>
<name>http.agent.description</name>
<value>MyTest</value>
<description>Further description</description>
</property>
<property>
<name>http.agent.url</name>
<value>gm1.nchc.org.tw</value>
<description>A URL to advertise in the User-Agent header. </description>
</property>
<property>
<name>http.agent.email</name>
<value>waue@nchc.org.tw</value>
<description>An email address
</description>
</property>
</configuration>
3.4 slaves
其實不用改,因為原本就是localhost
localhost
3.5 crawl-urlfilter.txt
將此檔的兩行改為下面內容
# skip URLs containing certain characters as probable queries, etc. -[*!@] # accept hosts in MY.DOMAIN.NAME +^http://([a-z0-9]*\.)*.*/
step 4 執行
4.1 編輯url清單
$ mkdir urls $ vim urls.txt
http://lucene.apache.org
4.2 開啟HDFS
$ bin/hadoop namenode -format $ bin/start-all.sh
4.3 上傳清單到HDFS
$ bin/hadoop -put urls urls
4.4 執行nutch crawl
$ bin/nutch crawl urls -dir crawl01 -depth 3
step 5 web瀏覽
5.1 安裝tomcat
- 下載
$ cd /opt/ $ wget http://ftp.twaren.net/Unix/Web/apache/tomcat/tomcat-6/v6.0.18/bin/apache-tomcat-6.0.18.tar.gz
- 解壓縮
$ tar -xzvf apache-tomcat-6.0.18.tar.gz $ mv apache-tomcat-6.0.18 tomcat
5.2 將crawl結果匯入tomcat
$ cd /opt/nutch $ mkdir web $ cd web $ jar -xvf nutch-1.0.war $ rm nutch-1.0.war $ mv /opt/tomcat/webapps/ROOT /opt/tomcat/webapps/ROOT-ori $ cd /opt/nutch $ mv /opt/nutch/web /opt/tomcat/webapps/ROOT $ vim /opt/tomcat/webapps/ROOT/WEB-INF/classes/nutch-site.xml
<configuration>
<property>
<name>searcher.dir</name>
<value>/opt/search</value>
</property>
</configuration>
並且修改 /opt/tomcat/conf/server.xml 以修正中文問題
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8"/>
5.3 瀏覽crawl結果
$ /opt/tomcat/bin/startup.sh
- 今天要來研究如何把nutch加入到已經在運作的hadoop上
- 續昨天,目錄結構如下
| /opt/nutch | nutch 家目錄 |
| /opt/nutch_conf | nutch設定檔 |
| /opt/hadoop | hadoop家目錄 |
| /opt/conf | hadoop設定檔 |
| /tmp/ | 日誌檔、中間檔與暫存檔 |
- 有可能的原因是nutch付的hadoop (0.19.1) 與我目前環境的hadoop (0.18.3)版本不同
- 由於大部分的情況是,我已經安裝了hadoop平台並且讓他工作一段時間之後,才要來加入nutch的測試,因此不可能在把以前的東西都刪掉,只為了測試nutch...
- 目前用 nutch官方文件所提供的概念,把nutch內的hadoop都替換為原本主機已經運行的hadoop,設定檔要設定對,並且注意把hadoop-env.sh的export參數都寫入bash.bashrc內,這麼做可以正確執行。
$ cp -rf /opt/hadoop/* /opt/nutch/ $ vim /opt/nutch_conf/slaves $ vim /opt/nutch_conf/nutch-site.xml $ vim /opt/nutch_conf/hadoop-site.xml $ scp -rc /opt/nutch_conf dx7200:/opt/nutch_conf $ scp -rc /opt/nutch dx7200:/opt/nutch
- 其他大致如昨天,但發現其實收尋的能力有限,幾乎只有到一層,需要解決搜尋能力的問題
- 目前已修改 nutch-site.xml的plugin.folder 與 plugin.plugin兩個屬性的值
- urls內的urls.txt也許也需要修改對應的網址
- 執行指令也有差
bin/nutch crawl urls -dir search -thread 5 -depth 5 -topN 5
- 目前正辛苦的運作中. good
- 備份ca日誌
- /root/backup.sh -> 將~/LOG內的資料打包 -> 備份 -> 清空LOG資料夾
- 根據昨天爬文結果,狀況不如預期,雖然總Job數比之前多,但可以搜尋到的資料很少,更不用提文件檔、pdf檔都沒爬文進去。
How can I recover an aborted fetch process? Well, you can not. However, you have two choices to proceed: % touch /index/segments/2005somesegment/fetcher.done % bin/nutch updatedb /index/db/ /index/segments/2005somesegment/ % bin/nutch generate /index/db/ /index/segments/2005somesegment/ % bin/nutch fetch /index/segments/2005somesegment How can I fetch only some sites at a time? # Use -topN to limit the amount of pages all together. # Use -numFetchers to generate multiple small segments. # Now you could either generate new segments. Maybe you whould use -adddays to allow bin/nutch generate to put all the urls in the new fetchlist again. Add more then 7 days if you did not make a updatedb. # Or send the process a unix STOP signal. You should be able to index the part of the segment for crawling which is allready fetched. Then later send a CONT signal to the process. Do not turn off your computer between! :) How many concurrent threads should I use? ulimit to 65535 (ulimit -n 65535), How can I force fetcher to use custom nutch-config? #Create a new sub-directory under $NUTCH_HOME/conf, like conf/myconfig #Copy these files from $NUTCH_HOME/conf to the new directory: common-terms.utf8, mime-types.*, nutch-conf.xsl, nutch-default.xml, regex-normalize.xml, regex-urlfilter.txt #Modify the nutch-default.xml to suite your needs #Set NUTCH_CONF_DIR environment variable to point into the directory you created #run $NUTCH_HOME/bin/nutch so that it gets the NUTCH_CONF_DIR environment variable. You should check the command outputs for lines where the configs are loaded, that they are really loaded from your custom dir. bin/nutch generate generates empty fetchlist, what can I do? Call bin/nutch generate with the -adddays 30 (if you haven't changed the default settings) to make generate think the time has come... After generate you can call bin/nutch fetch. How can I fetch pages that require Authentication? See HttpAuthenticationSchemes. Is it possible to change the list of common words without crawling everything again? Yes. The list of common words is used only when indexing and searching, and not during other steps. How do I index my local file system 1) crawl-urlfilter.txt needs a change to allow file: URLs while not following http: ones, otherwise it either won't index anything, or it'll jump off your disk onto web sites. Change this line: -^(file|ftp|mailto|https): to this: -^(http|ftp|mailto|https): 2) crawl-urlfilter.txt may have rules at the bottom to reject some URLs. If it has this fragment it's probably ok: # accept anything else +.* 3) By default the [WWW] "file plugin" is disabled. nutch-site.xml needs to be modified to allow this plugin. Add an entry like this: <property> <name>plugin.includes</name> <value>protocol-file|protocol-http|parse-(text|html)|index-basic|query-(basic|site|url)</value> </property> What is happening? By default, the size of the documents downloaded by Nutch is limited (to 65536 bytes). To allow Nutch to download larger files (via HTTP), modify nutch-site.xml and add an entry like this: <property> <name>http.content.limit</name> <value>150000</value> </property> If you do not want to limit the size of downloaded documents, set http.content.limit to a negative value: <property> <name>http.content.limit</name> <value>-1</value> </property> How can I find out/display the size and mime type of the hits that a search returns? <property> <name>plugin.includes</name> <value>...|index-more|...|query-more|...</value> ... </property> Nutch doesn't crawl relative URLs? Some pages are not indexed but my regex file and everything else is okay - what is going on? The crawl tool has a default limitation of 100 outlinks of one page that are being fetched. <property> <name>db.max.outlinks.per.page</name> <value>-1</value> <description> </description> </property>
- 上面有些有用的訊息,但不見得可以解決遇到的問題,至少可以看crawl.log ,看他都fetch , index了哪些網址
前言
- 雖然之前已經測試過了,網路上也有許多人分享過成功的經驗,然而這篇的重點
- 完整的安裝nutch,並解決中文亂碼問題
- 用hadoop的角度來架設nutch
- 搜尋引擎不只是找網頁內的資料,也能爬到網頁內的檔案(如pdf,msword)
環境
- 目錄
| /opt/nutch | nutch 家目錄 |
| /opt/nutch_conf | nutch設定檔 |
| /opt/hadoop | hadoop家目錄 |
| /opt/conf | hadoop設定檔 |
| /tmp/hadoop/ /tmp/nutch | 日誌檔、中間檔與暫存檔 |
step 1 安裝好Hadoop叢集
- 可以參考這篇 hadoop叢集安裝
- 當然單機版也可以,只是這樣就直接安裝nutch更省事囉!單機安裝nutch可以參考這裡nutch單機安裝,但是設定檔要參考這篇的才完整。
- 安裝好hadoop 叢集之後,/opt/的權限就是使用者的了,並且ssh登入兩台都免密碼,hadoop也能正常執行,並且安裝於/opt/hadoop下,設定檔在 /opt/conf
step 2 下載與安裝
2.1 下載 nutch 並解壓縮
- nutch 1.0 (2009/03/28 release )
$ cd /opt $ wget http://ftp.twaren.net/Unix/Web/apache/lucene/nutch/nutch-1.0.tar.gz $ tar -zxvf nutch-1.0.tar.gz $ mv nutch-1.0.tar.gz nutch
2.2 部屬hadoop,nutch目錄結構
$ mv nutch/conf ./nutch_conf $ cp -rf conf/* nutch_conf $ cp -rf hadoop/* nutch
- 做完以上動作,nutch的設定檔就會被放在/opt/nutch_conf下,並且把現有hadoop的設定(/opt/conf)帶進nutch的設定中,而nutch_home內的hadoop執行檔也會跟正在運行的hadoop同個版本。
- 以上的目錄結構在於nutch與hadoop分離,主程式與設定檔分離,(日誌檔則統一被紀錄到/tmp中),這樣的目的在於,要刪除nutch的話直接移除目錄就好,不會動到原本的hadoop。
step 3 編輯設定檔
- 所有的設定檔都在 /opt/nutch_conf 下
3.1 hadoop-env.sh
- 將原本的檔案hadoop-env.sh任意處填入
export JAVA_HOME=/usr/lib/jvm/java-6-sun export HADOOP_HOME=/opt/nutch export HADOOP_CONF_DIR=/opt/nutch_conf export HADOOP_SLAVES=$HADOOP_CONF_DIR/slaves export HADOOP_LOG_DIR=/tmp/hadoop/logs export HADOOP_PID_DIR=/tmp/hadoop/pid export NUTCH_HOME=/opt/nutch export NUTCH_CONF_DIR=/opt/nutch_conf
- 載入環境設定值
$ source /opt/nutch_conf/hadoop-env.sh
- ps:強烈建議寫入 /etc/bash.bashrc 中比較萬無一失!!
3.2 hadoop-site.xml
<configuration>
<property>
<name>fs.default.name</name>
<value>hdfs://node1:9000/</value>
<description> </description>
</property>
<property>
<name>mapred.job.tracker</name>
<value>node1:9001</value>
<description> </description>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/tmp/hadoop/hadoop-${user.name}</value>
<description> </description>
</property>
</configuration>
3.3 nutch-site.xml
- 重要的設定檔,新增了必要的內容於內,然而想要瞭解更多參數資訊,請見nutch-default.xml
<configuration> <property> <name>http.agent.name</name> <value>nutch</value> <description>HTTP 'User-Agent' request header. </description> </property> <property> <name>http.agent.description</name> <value>nutch-crawl</value> <description>Further description</description> </property> <property> <name>http.agent.url</name> <value>node1</value> <description>A URL to advertise in the User-Agent header. </description> </property> <property> <name>http.agent.email</name> <value>user@nchc.org.tw</value> <description>An email address </description> </property> <property> <name>plugin.folders</name> <value>/opt/nutch/plugins</value> <description>Directories where nutch plugins are located. </description> </property> <property> <name>plugin.includes</name> <value>protocol-(http|httpclient)|urlfilter-regex|parse-(text|html|js|ext|msexcel|mspowerpoint|msword|oo|pdf|rss|swf|zip)|index-(more|basic|anchor)|query-(more|basic|site|url)|response-(json|xml)|summary-basic|scoring-opic|urlnormalizer-(pass|regex|basic)</value> <description> Regular expression naming plugin directory names</description> </property> <property> <name>parse.plugin.file</name> <value>parse-plugins.xml</value> <description>The name of the file that defines the associations between content-types and parsers.</description> </property> <property> <name>db.max.outlinks.per.page</name> <value>-1</value> <description> </description> </property> <property> <name>http.content.limit</name> <value>-1</value> </property> <property> <property> <name>indexer.mergeFactor</name> <value>500</value> <description>The factor that determines the frequency of Lucene segment merges. </description> </property> <property> <name>indexer.minMergeDocs</name> <value>500</value> <description>This number determines the minimum number of Lucene. </description> </property> </configuration>
3.4 slaves
- 這個檔不用設定,因為依照hadoop的叢集環境,下面列出我們環境所設定的
node1 node2
3.5 crawl-urlfilter.txt
- 重新編輯爬檔規則,此檔重要在於若設定不好,則爬出來的結果幾乎是空的,也就是說最後你的搜尋引擎都找不到資料啦!
# skip ftp:, & mailto: urls -^(ftp|mailto): # skip image and other suffixes we can't yet parse -\.(gif|GIF|jpg|JPG|png|PNG|ico|ICO|css|sit|eps|wmf|mpg|xls|gz|rpm|tgz|mov|MOV|exe|jpeg|JPEG|bmp|BMP)$ # skip URLs containing certain characters as probable queries, etc. -[*!@] # accecpt anything else +.*
3.6 regex-urlfilter.txt
- 雖然官方網站鮮少介紹到此檔,但是crawl-urlfilter.txt用來設定爬intranet的規則,而regex-urlfilter.txt則是用來設定爬internet的規則
$ cd /opt/nutch_conf $ cp regex-urlfilter.txt regex-urlfilter.txt-bek $ cp crawl-urlfilter.txt regex-urlfilter.txt
3.7 整個移植到另一台node
$ ssh node02 "sudo chown hadooper:hadooper /opt" $ scp -r /opt/nutch node02:/opt/
step 4 執行nutch
- 在此假設你已經把hadoop 啟動並且正在運作了。因此nutch是利用這個已經在運做的平台上
- 如果你的hadoop還沒啟動,則請在master節點(此篇以node1當作master)下 bin/start-all.sh指令;如果你的環境很clean,則請在master節點下
- 到/opt/nutch 或 /opt/hadoop皆可
$ cd /opt/nutch $ bin/hadoop namenode -format $ bin/start-all.sh
- 到/opt/nutch 或 /opt/hadoop皆可
4.1 編輯url清單
$ mkdir urls $ vim urls.txt
http://www.nchc.org.tw
4.2 上傳清單到HDFS
$ bin/hadoop -put urls urls
4.3 執行nutch crawl
- 用下面的指令就可以命令nutch開始工作了,之後map reduce會瘋狂工作
$ bin/nutch crawl urls -dir search -threads 2 -depth 3 -topN 100000
- 執行上個指令會把執行過程秀在stdout上。若想要以後慢慢看這些訊息,可以用io導向的方式傾倒於日誌檔
$ bin/nutch crawl urls -dir search -threads 2 -depth 3 -topN 100000 >& nutch.log
- 執行上個指令會把執行過程秀在stdout上。若想要以後慢慢看這些訊息,可以用io導向的方式傾倒於日誌檔
- 在nutch運作的同時,可以在node1節點用瀏覽器,透過 job管理頁面, hdfs管理頁面, 程序運作頁面 來監看程序。
step 5 瀏覽搜尋結果
- nutch 在 step 4 的工作是把你寫在urls.txt檔內的網址,用map reduce的程序來進行資料分析,但是分析完之後,要透過tomcat來觀看結果。以下就是安裝與設定你的客製化搜尋引擎的步驟。
5.1 安裝tomcat
- 下載tomcat
$ cd /opt/ $ wget http://ftp.twaren.net/Unix/Web/apache/tomcat/tomcat-6/v6.0.18/bin/apache-tomcat-6.0.18.tar.gz
- 解壓縮
$ tar -xzvf apache-tomcat-6.0.18.tar.gz $ mv apache-tomcat-6.0.18 tomcat
5.1 tomcat server設定
- 修改 /opt/tomcat/conf/server.xml 以修正中文亂碼問題
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8" useBodyEncodingForURI="true" />
5.3 下載crawl結果
- 先把放在hdfs上,nutch的運算結果下載到local端
$ cd /opt/nutch $ bin/hadoop dfs -get search /opt/search
5.4 設定nutch的搜尋引擎頁面到tomcat
- 把nutch的搜尋引擎頁面取代為tomcat的webapps/ROOT
$ cd /opt/nutch $ mkdir web $ cd web $ jar -xvf ../nutch-1.0.war $ rm nutch-1.0.war $ mv /opt/tomcat/webapps/ROOT /opt/tomcat/webapps/ROOT-ori $ cd /opt/nutch $ mv /opt/nutch/web /opt/tomcat/webapps/ROOT
5.5 設定搜尋引擎內容的來源路徑
- 5.4的步驟雖然設定好搜尋引擎的頁面,然而其只能當作是介面而已,因此這個步驟把要搜尋的內容與搜尋介面做個連結
$ vim /opt/tomcat/webapps/ROOT/WEB-INF/classes/nutch-site.xml
<configuration>
<property>
<name>searcher.dir</name>
<value>/opt/search</value>
</property>
</configuration>
5.6 啟動tomcat
$ /opt/tomcat/bin/startup.sh
step 6 享受結果
Enjoy ! http://localhost:8080
- 更新ca的openssl -> 0.9.8k (2009/03/25 release)
- 更新方式: 下載tar ball, ./config ; make ; make test; make install
- 今天測試了hadoop 新版本與eclipse的關係,發現
| hadoop 版本 | eclipse | 狀態 |
| 0.16.4 | 3.2 | 一切正常 |
| 0.18.3 | 3.4 | 都正常,但無法"run on hadoop" |
| 0.19.1 | 3.4 | 無法使用 |
- 今天繼續測試了 contrib/eclipse-plugin/hadoop-*-jar 與 eclipse 版本的關係,發現昨天在eclipse 3.4可以run的hadoop-0.18.3-plugin.jar 今天也不行了。
- 下載來 eclipse 3.3 來測試,也有奇怪的問題,也許是我的ubuntu怪怪的。
- 我的ubuntu 用apt-get install eclipse 所安裝的eclipse 無法執行,console端也沒出現錯誤訊息,直接下載eclipse-3.2~3.4-SDK的linux版本來測試就遇到這麼多奇奇怪怪的問題,搞得有點令人傷腦筋 XD
- 文傑分享虛擬機器實務
前言
- 繼文傑大大昨天講了虛擬運算的課之後,收穫良多。其中又看到大大已經註冊並使用aws,因此傚法他的精神,也來申請來使用一下
- Tsung's Blog 看到詳細介紹,算是入門必讀的文件(我就是沒看這篇亂入,所以多花了一些時間摸索 XD)
aws 首頁
輸入帳號密碼
登入畫面
- 選擇My Account-> AWS Manage Console
AWS Manage Console
選擇EC2頁面
- 選擇 launch a AMI
Amazon 預設的映像檔
第三方提供的映像檔
輸入條件選擇我們要的AMI
選擇後的總覽
生成登入要用的憑證
EC2完成
用憑證登入虛擬機器EC2
$ ssh -i wauekey.pem root@ec2-67-202-57-153.compute-1.amazonaws.com
__| __|_ ) Fedora 8
_| ( / 32-bit
___|\___|___|
Welcome to an EC2 Public Image
:-)
Base
[root@domU-12-31-39-00-C5-A3 ~]#
EC2的MapReduce工作發送頁面
你Amazon的費用統計
連入aws的兩種方式
結論
- 雖然成功生成虛擬機器一台,不過在以上操作中沒有使用到amazon所提供的firefox擴充套件:Elasticfox ,據說可以用網頁連入主機,而不用另開ssh
- 網頁所說得連入aws的兩種方式:assess id 與 憑證,在以上操作下都沒有使用到
- 雖然用了EC2,不過這台虛擬機器的儲存空間不明,因為我沒有買S3。
- 今天主要的工作就是準備4/22的cloudslam 09的演講
- 不過由於前幾天測試了aws,覺得相當有趣,後來也試用了一下azure,這邊簡單紀錄一下
- 在寫使用azure之前,先推薦一個網址 開發 Windows Azure 應用程式的第一步:註冊、下載、學習
- 由於註冊在好幾天之前就做了,今天收到invite code,才算是註冊完整,因此事隔太久,已無法完全重現。不過最終註冊後並完成填入invite code的結果如圖:
ps : 注意!!! 紅框是標明註冊後並填入Token,才會出現大於1的專案數給你開啟,否則只是註冊沒有登入token,上面兩個的專案數皆為0
1. 先到 http://www.microsoft.com/taiwan/azure/signin.htm 台灣的azure網站登入吧!
2. 填寫資料,請他送註冊資訊到信箱,過了好幾天之後會送類似像此封信件
3. 有了這封信,並非直接點選該連結就可以了,而是進了畫面之後,選擇 "Account" -> "Manage My Tokens" -> 填入信件中所說得code -> 完成
- nchc ca current status presentation
- audit ... ?
- ca manber change -> cp/cps update
the slide about job modification
- slide should be only showed the update issue
- CA sign can use the openca
- 做cloud slam 09 投影片
- cloudslam09 報告 (am 8:00 ~ am 9:00)
- 建立 slideshare 帳號 http://www.slideshare.net/waue
- 修改4/27~28 授課投影片
- 製作nutch投影片
- 製作nutch安裝使用教學
- nutch相關
- Heritrix
- SOLR
- 準備環境電腦教室環境 .. ok
- 製作nutch實作課程
- 製作cluster進階使用課程
- 雲端運算基礎課程開課
- 雲端運算基礎課程開課
- 測試 opensolaris hadoop live cd
- 此測試版為 opensolaris + hadoop 0.17.1 的live cd
- 用此片開機完之後,點擊桌面的start-mapreduce圖示就開啟了hadoop 叢集環境
- 此hadoop叢集環境為 192.168.50.1 namenode -> < 192.168.50.11 slave node > & < 192.168.50.12 slave node >
- 預計此系統另開啟兩台vm以提供slave的角色,至於vm用何軟體產生目前不明...
cloud base
- 說明: cloudbase 在目前使用過的解讀下,可稱之為運用在hadoop的database,可以輕易的使用sql語法進行hadoop資料的分析。
- 與hbase的不同:目前認為,cloud base比hbase 方便的一點在於,hbase必須在mapreduce的程式碼中加入把結果塞入hbase的code,而cloud卻不用,只要把cloud執行起來之後,他就會不斷的監聽hadoop並將hadoop的結果自行紀錄於自己的database,如此一來只要對cloud base進行sql的語法查詢就可以撈出資訊
安裝步驟
step 0: 準備相關軟件:
下載hadoop-0.18.3.tar.gz
http://www.apache.org/dist/hadoop/core/hadoop-0.18.3/hadoop-0.18.3.tar.gz
下載cloudbase最新版(目前使用 cloudbase 1.3)
http://sourceforge.net/projects/cloudbase
http://downloads.sourceforge.net/cloudbase/cloudbase-1.3.tar.gz?use_mirror=jaist
step 1 : 安裝設定hadoop
- 請參考之前的hadoop安裝教學 或 nutch 的安裝教學
- 執行到start-all.sh ,亦即啟動hadoop環境並執行中...
- 確認服務正常:
$ jps 24376 NameNode 24471 DataNode 24579 SecondaryNameNode 24882 JobShell 24665 JobTracker 24769 TaskTracker 28090 Jps $
- 確認服務正常:
step 2 : 啟動CloudBase
- 安裝cloudbase
$ cd /opt/ $ tar xvzf cloudbase-1.3.tar.gz $ ln -sf /opt/cloudbase-1.3 /opt/cloudbase
- 修改 cloudbase-env
$ vim /opt/cloudbase/bin/cloudbase-env
- 內容為:
# Set the hadoop home dir HADOOP_HOME=/home/hadoop/hadoop export HADOOP_HOME
- 內容為:
- 啟動 cloudbase
$ cd /opt/cloudbase/bin/ $ ./start-cloudbase &
- 記得執行$cloudbase/test/bin/setup 以建立測試的資料表(此步驟連官網都沒有,但最後一直沒有test_table出現,找了很久才找到要執行此步)
step 3 : 用SQuirreL SQL 檢視
首先下載client 端軟件,SQuirreL SQL Client 。
http://squirrel-sql.sourceforge.net/
http://jaist.dl.sourceforge.net/sourceforge/squirrel-sql/squirrel-sql-3.0-install.jar
執行點擊兩下下載下來的 squirrel-sql-3.0-install.jar即可安裝,下一步即可\
- Drivers -> New Driver -> name: CloudBase JDBC Driver , example url : jdbc:cloudbase://localhost:4444, class name : com.business.cloudbase.CBDriver , ultra class path : /opt/cloudbase/build/jar/cloudbasejdbc-1.3.jar -> ok
- Aliases -> user : test , password: test -> connect
- SQL -> select * FROM test_table1 -> 點小黑人在跑的圖示 -> 就有結果出現囉!
- enjoy
CloudBase 簡介
- cloudbase 為運用在hadoop的database,可以輕易的使用sql語法進行hadoop資料的分析。
- 每次進行sql的查詢時,hadoop就會進行mapreduce來解析,最後在呈現出結果。
- CloudBase 與 Hive 類似,只有一些sql的語法不同,然而架構與用途相同。Hive已經包含於hadoop 0.19內
- 與hbase的不同為,hbase必須在mapreduce的程式碼中加入把結果塞入hbase的程式碼;而cloudbase卻不用,只要將結果放在 hdfs://user/$USER/cloudbase/data/$TABLE_Name/$TABLE_Name, 如:/user/waue/cloudbase/data/test_table1/test_table1 ,並且內容格式如下,即為cloudbase的資料檔
ipod|50|20.57|www.google.com ipod|10|10.25|www.google.com ipod|15|11.65|www.yahoo.com ipod|-20|-33.67|www.msn.com ipod|85|36.57|www.google.com zune|5|15.7|www.google.com zune|3|12.1|www.msn.com zune|10|6.5|www.msn.com iriver|30|15.5|www.yahoo.com iriver|45|12.3|www.yahoo.com iriver|25|16.7|www.yahoo.com iriver|15|15.3|www.yahoo.com iriver|20|18.0|www.yahoo.com iriver|16|20|www.google.com - CloudBase 提供了四種方法來讓使用者query資料 ( http://cloudbase.sourceforge.net/index.html#userDoc)
- python (執行cloudbase提供的python的程式)
- java (用JDBC )
- cli (JiSQL )
- squirrel (圖形介面程式)
- 舉例來說,在squirrel執行 "select * from test_table1" 就出現如下結果
安裝步驟
step 0: 準備相關軟件:
下載hadoop-0.18.3.tar.gz
http://www.apache.org/dist/hadoop/core/hadoop-0.18.3/hadoop-0.18.3.tar.gz
下載cloudbase最新版(目前使用 cloudbase 1.3)
http://sourceforge.net/projects/cloudbase
http://downloads.sourceforge.net/cloudbase/cloudbase-1.3.tar.gz?use_mirror=jaist
step 1 : 安裝設定hadoop
- 請參考之前的hadoop安裝教學 或 nutch 的安裝教學
- 執行到start-all.sh ,亦即啟動hadoop環境並執行中...
- 確認服務正常:
$ jps 24376 NameNode 24471 DataNode 24579 SecondaryNameNode 24882 JobShell 24665 JobTracker 24769 TaskTracker 28090 Jps
step 2 : 啟動CloudBase
- 安裝cloudbase
$ cd /opt/ $ tar xvzf cloudbase-1.3.tar.gz $ ln -sf /opt/cloudbase-1.3 /opt/cloudbase
- 修改 cloudbase-env
$ vim /opt/cloudbase/bin/cloudbase-env
- 內容為:
# Set the hadoop home dir HADOOP_HOME=/home/hadoop/hadoop export HADOOP_HOME
- 內容為:
- 啟動 cloudbase
$ cd /opt/cloudbase/bin/ $ ./start-cloudbase &
- 記得執行$cloudbase/test/bin/setup 以建立測試的資料表(此步驟連官網都沒有,但最後一直沒有test_table出現,找了很久才找到要執行此步)
step 3 : 用SQuirreL SQL 檢視
- 首先下載client 端軟件,SQuirreL SQL Client 。
- 執行點擊兩下下載下來的 squirrel-sql-3.0-install.jar即可安裝,下一步即可
- 執行squirrel ,跑出主程式頁面,並執行以下操作
- Drivers -> New Driver ->
name CloudBase JDBC Driver example url jdbc:cloudbase://localhost:4444 class name com.business.cloudbase.CBDriver ultra class path /opt/cloudbase/build/jar/cloudbasejdbc-1.3.jar -> ok
- Aliases ->
user test password test -> connect
- SQL -> select * FROM test_table1 -> 點小黑人在跑的圖示 -> 就有結果出現囉!
}}}
- enjoy
- 當執行sql語法時,可以到localhost:50030觀查到,hadoop被呼叫來執行mapreduce的工作。而cloudbase的console端也能看到完整的log如下
GOT SQL: select t1.c1, t1.c2, t1.c3, t1.c4, t2.c1, t2.c2, t2.c3, t2.c4 from test_table4 t1 inner join test_table5 t2 on t1.c1 = t2.c1 order by 1,2,3,4,5,6,7,8 09/05/05 14:12:07 WARN mapred.JobClient: Use GenericOptionsParser for parsing the arguments. Applications should implement Tool for the same. 09/05/05 14:12:07 INFO mapred.FileInputFormat: Total input paths to process : 1 09/05/05 14:12:07 INFO mapred.FileInputFormat: Total input paths to process : 1 09/05/05 14:12:07 INFO mapred.JobClient: Running job: job_200905010939_0030 09/05/05 14:12:08 INFO mapred.JobClient: map 0% reduce 0% 09/05/05 14:12:12 INFO mapred.JobClient: map 100% reduce 0% 09/05/05 14:12:17 INFO mapred.JobClient: Job complete: job_200905010939_0030 09/05/05 14:12:17 INFO mapred.JobClient: Counters: 16 09/05/05 14:12:17 INFO mapred.JobClient: File Systems 09/05/05 14:12:17 INFO mapred.JobClient: HDFS bytes read=207 09/05/05 14:12:17 INFO mapred.JobClient: HDFS bytes written=461 09/05/05 14:12:17 INFO mapred.JobClient: Local bytes read=159 09/05/05 14:12:17 INFO mapred.JobClient: Local bytes written=404 ~~~~ 略 ~~~~~ 09/05/05 14:14:21 INFO mapred.JobClient: Job Counters 09/05/05 14:14:21 INFO mapred.JobClient: Launched map tasks=2 09/05/05 14:14:21 INFO mapred.JobClient: Data-local map tasks=2 09/05/05 14:14:21 INFO mapred.JobClient: Map-Reduce Framework 09/05/05 14:14:21 INFO mapred.JobClient: Map input records=7 09/05/05 14:14:21 INFO mapred.JobClient: Map input bytes=201 09/05/05 14:14:21 INFO mapred.JobClient: Map output records=7
簡介
- Hive 是由facebook所捐贈給hadoop的項目
- 功能類似前一天測試的cloudbase
- 更簡便的一點是,Hive 已經整合在 Hadoop 0.19.1的版本內(但 0.20.0 卻又不見了),幾乎不用特別座設定,並且也有提供自己的交互查詢模式,就不用特別在安裝其他東西了
- 感覺上操作起來有點像hbase !!
- 缺點是:沒有help,不知道到底有什麼語法可用
安裝
在 hadoop 0.19.1 的 contrib 內已有 hive 的專案,先匯入環境變數後在進到此資料夾執行hive就可以使用了
$ export HADOOP=/opt/hadoop/ $ export HIVE_HOME=/opt/hadoop/contrib/hive/ $ cd /opt/hadoop/contrib/hive $ bin/hive hive>
測試
hive> CREATE TABLE pokes (foo INT, bar STRING);
輸出如:
OK Time taken: 0.251 seconds
- 執行
hive> CREATE TABLE invites (foo INT, bar STRING) PARTITIONED BY (ds STRING);
輸出如:
OK Time taken: 0.106 seconds
- 執行
hive> SHOW TABLES;
輸出如:
OK invites pokes Time taken: 0.107 seconds
- 執行
hive> DESCRIBE invites;
輸出如:
OK foo int bar string ds string Time taken: 0.151 seconds
- 執行
hive> ALTER TABLE pokes ADD COLUMNS (new_col INT);
輸出如:
OK Time taken: 0.117 seconds
- 執行
hive> ALTER TABLE invites ADD COLUMNS (new_col2 INT COMMENT 'a comment');
輸出如:
OK Time taken: 0.152 seconds
- 執行
hive> LOAD DATA LOCAL INPATH './examples/files/kv1.txt' OVERWRITE INTO TABLE pokes;
輸出如:
Copying data from file:/home/hadoop/hadoop-0.19.1/contrib/hive/examples/files/kv1.txt Loading data to table pokes OK Time taken: 0.288 seconds
- 執行
hive> LOAD DATA LOCAL INPATH './examples/files/kv2.txt' OVERWRITE INTO TABLE invites PARTITION (ds='2008-08-15');
輸出如:
Copying data from file:/home/hadoop/hadoop-0.19.1/contrib/hive/examples/files/kv2.txt Loading data to table invites partition {ds=2008-08-15} OK Time taken: 0.524 seconds
- 執行
hive> LOAD DATA LOCAL INPATH './examples/files/kv3.txt' OVERWRITE INTO TABLE invites PARTITION (ds='2008-08-08');
輸出如:
Copying data from file:/home/hadoop/hadoop-0.19.1/contrib/hive/examples/files/kv3.txt Loading data to table invites partition {ds=2008-08-08} OK Time taken: 0.406 seconds
- 執行
hive> INSERT OVERWRITE DIRECTORY '/tmp/hdfs_out' SELECT a.* FROM invites a;
輸出如:
Total MapReduce jobs = 1 Starting Job = job_200902261245_0002, Tracking URL = http://gp1:50030/jobdetails.jsp?jobid=job_200902261245_0002 Kill Command = /home/hadoop/hadoop-0.19.1/bin/hadoop job -Dmapred.job.tracker=gp1:9001 -kill job_200902261245_0002 map = 0%, reduce =0% map = 50%, reduce =0% map = 100%, reduce =0% Ended Job = job_200902261245_0002 Moving data to: /tmp/hdfs_out OK Time taken: 18.551 seconds
- 執行
hive> select count(1) from pokes;
輸出如:
Total MapReduce jobs = 2 Number of reducers = 1 In order to change numer of reducers use: set mapred.reduce.tasks = <number> Starting Job = job_200902261245_0003, Tracking URL = http://gp1:50030/jobdetails.jsp?jobid=job_200902261245_0003 Kill Command = /home/hadoop/hadoop-0.19.1/bin/hadoop job -Dmapred.job.tracker=gp1:9001 -kill job_200902261245_0003 map = 0%, reduce =0% map = 50%, reduce =0% map = 100%, reduce =0% map = 100%, reduce =17% map = 100%, reduce =100% Ended Job = job_200902261245_0003 Starting Job = job_200902261245_0004, Tracking URL = http://gp1:50030/jobdetails.jsp?jobid=job_200902261245_0004 Kill Command = /home/hadoop/hadoop-0.19.1/bin/hadoop job -Dmapred.job.tracker=gp1:9001 -kill job_200902261245_0004 map = 0%, reduce =0% map = 50%, reduce =0% map = 100%, reduce =0% map = 100%, reduce =100% Ended Job = job_200902261245_0004 OK 500 Time taken: 57.285 seconds
- 執行
hive> INSERT OVERWRITE DIRECTORY '/tmp/hdfs_out' SELECT a.* FROM invites a;
輸出如:
Total MapReduce jobs = 1 Starting Job = job_200902261245_0005, Tracking URL = http://gp1:50030/jobdetails.jsp?jobid=job_200902261245_0005 Kill Command = /home/hadoop/hadoop-0.19.1/bin/hadoop job -Dmapred.job.tracker=gp1:9001 -kill job_200902261245_0005 map = 0%, reduce =0% map = 50%, reduce =0% map = 100%, reduce =0% Ended Job = job_200902261245_0005 Moving data to: /tmp/hdfs_out OK Time taken: 18.349 seconds
- 執行
hive> INSERT OVERWRITE DIRECTORY '/tmp/reg_5' SELECT COUNT(1) FROM invites a;
輸出如:
Total MapReduce jobs = 2 Number of reducers = 1 In order to change numer of reducers use: set mapred.reduce.tasks = <number> Starting Job = job_200902261245_0006, Tracking URL = http://gp1:50030/jobdetails.jsp?jobid=job_200902261245_0006 Kill Command = /home/hadoop/hadoop-0.19.1/bin/hadoop job -Dmapred.job.tracker=gp1:9001 -kill job_200902261245_0006 map = 0%, reduce =0% map = 50%, reduce =0% map = 100%, reduce =0% map = 100%, reduce =17% map = 100%, reduce =100% Ended Job = job_200902261245_0006 Starting Job = job_200902261245_0007, Tracking URL = http://gp1:50030/jobdetails.jsp?jobid=job_200902261245_0007 Kill Command = /home/hadoop/hadoop-0.19.1/bin/hadoop job -Dmapred.job.tracker=gp1:9001 -kill job_200902261245_0007 map = 0%, reduce =0% map = 50%, reduce =0% map = 100%, reduce =0% map = 100%, reduce =17% map = 100%, reduce =100% Ended Job = job_200902261245_0007 Moving data to: /tmp/reg_5 OK Time taken: 70.956 seconds
資料庫內的資料
- 存在於 hdfs://user/hive/warehouse 內,一個table為一個資料夾
vim 進階
- 今天讀了" 大家來學vim"的電子書,收穫良多
- 目前看到第十章,正規表示法以前,不過應該夠了,今天讀的能記起熟用即可
* h , j , l , k , w , b, ( , ) , ^ , $ , G , gg * v 與 ctrl +v 的用法 , >> , << * 5"ayy , * 5"Ayy , :reg * :set all , :opt , * # , * , / * :%s///g * :ls , :b , :e , :w , :n , :N * ma , 'a * :paste * y5yp , . , * ctrl w n , ctrl w j , ctrl w k , * :!ls ,
本月目標 :
- nutch 打包
- dialog設計 nutch 的conf
- python & perl
- jquery
前言
- 要學習如何包裝nutch 的 deb檔
- 然而目前大部分找到的說明是適用於 c code等要configure , make , make install 的專案,才會很簡單的用以下方法來完成製作deb
- 目錄名稱如 pkgname-version ,例: hadoop-0.19
- 在source code內執行dh_make
- 修改 新產生debian資料夾內的設定檔
- 執行dpkg-buildpackage -rfakeroot
- 不過hadoop 與 nutch都是java code,沒有make or configure檔,因此試過上面的方法會遇到錯誤
- 因此此篇適合用在:打包已經compiler好的可執行檔,並搭配設定好的配置檔來做簡便安裝用途者
步驟
製作deb打包設定檔
$ mkdir -p ~/test/hadoop-0.19.1/debian $ cd ~/test/hadoop-0.19.1/debian
編輯檔案
- 這些與dh_make產生出來的檔案差不多,就不討論了
| changelog |
| copyright |
| compat |
| control |
- 以下檔案就把內容列出
rules
#!/usr/bin/make -f export DH_VERBOSE=0 all: install: dh_testdir dh_testroot dh_install -Xlicense.txt dh_installdocs dh_installchangelogs #dh_installexamples dh_compress dh_fixperms dh_installdeb dh_link dh_gencontrol dh_md5sums dh_builddeb clean: dh_clean binary: install build: binary-arch: binary-indep:
control
Source: hadoop Section: devel Priority: extra Maintainer: Jazz Yao-Tsung Wang <jazzwang.tw@gmail.com> Build-Depends: debhelper (>= 5) Standards-Version: 3.7.2 Package: hadoop Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, sun-java6-jre, sun-java6-bin Suggests: sun-java6-jdk Description: Apache Hadoop Core . Apache Hadoop Core is a software platform that lets one easily write and run applications that process vast amounts of data. . Here's what makes Hadoop especially useful: * Scalable: Hadoop can reliably store and process petabytes. * Economical: It distributes the data and processing across clusters of commonly available computers. These clusters can number into the thousands of nodes. * Efficient: By distributing the data, Hadoop can process it in parallel on the nodes where the data is located. This makes it extremely rapid. * Reliable: Hadoop automatically maintains multiple copies of data and automatically redeploys computing tasks based on failures. . Hadoop implements MapReduce, using the Hadoop Distributed File System (HDFS) MapReduce divides applications into many small blocks of work. HDFS creates multiple replicas of data blocks for reliability, placing them on compute nodes around the cluster. MapReduce can then process the data where it is located. . For more information about Hadoop, please see the Hadoop website. http://hadoop.apache.org/ Package: hadoop-src Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, sun-java6-jdk, ant, gcc, g++, hadoop Description: Apache Hadoop Core ( java source code and examples ) . Apache Hadoop Core is a software platform that lets one easily write and run applications that process vast amounts of data. . This package include the java source code and examples from original tarball. Install this package only when you need to rebuild the jar binary or want to run the 'Word Count' examples of MapReduce. Package: hadoop-doc Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: Apache Hadoop Core Documents . Apache Hadoop Core is a software platform that lets one easily write and run applications that process vast amounts of data. . This package include the HTML and PDF documents from original tarball. Install this package only when you need these documents.
hadoop.install
conf/* etc/hadoop debian/conf/* etc/hadoop bin opt/hadoop c++ opt/hadoop contrib opt/hadoop lib opt/hadoop libhdfs opt/hadoop librecordio opt/hadoop webapps opt/hadoop *.jar opt/hadoop
hadoop.prerm
#!/bin/sh
su -c /opt/hadoop/bin/stop-all.sh hdfsadm -
hadoop-doc.install
docs/* usr/share/doc/hadoop
hadoop.links
etc/hadoop opt/hadoop/conf usr/share/doc/hadoop opt/hadoop/docs var/log/hadoop opt/hadoop/logs
hadoop-src.install
src opt/hadoop *.xml opt/hadoop
hadoop-doc.links
usr/share/doc/hadoop opt/hadoop/docs
hadoop.postinst
#!/bin/sh echo "$1" if [ "$1" != configure ] then exit 0 fi setup_hdfsadm_user() { if ! getent passwd hdfsadm >/dev/null; then useradd hdfsadm mkdir -p /home/hdfsadm/.ssh mkdir -p /var/log/hadoop ssh-keygen -t rsa -q -f /home/hdfsadm/.ssh/id_rsa -N "" cp /home/hdfsadm/.ssh/id_rsa.pub /home/hdfsadm/.ssh/authorized_keys chown hdfsadm:hdfsadm /var/log/hadoop chown -R hdfsadm:hdfsadm /home/hdfsadm/.ssh chown -R hdfsadm:hdfsadm /home/hdfsadm su -c "/opt/hadoop/bin/hadoop namenode -format" hdfsadm - su -c /opt/hadoop/bin/start-all.sh hdfsadm - echo "Please check via browsing following URLs:" echo "(1) http://localhost:50030 for Hadoop Map/Reduce Administration." echo "(2) http://localhost:50060 for Hadoop Task Tracker status" echo "(3) http://localhost:50070 for Hadoop Distributed File System status" fi } setup_hdfsadm_user
hadoop.docs
CHANGES.txt LICENSE.txt NOTICE.txt README.txt
hadoop.postrm
#!/bin/sh echo "$1" if [ "$1" != remove ] then exit 0 fi setup_hdfsadm_user() { if ! getent passwd hdfsadm >/dev/null; then echo "no account found: 'hdfsadm'." else userdel hdfsadm rm -rf /home/hdfsadm rm -rf /var/log/hadoop rm -rf /tmp/hadoop-hdfsadm* rm -rf /tmp/hsperfdata_* fi } setup_hdfsadm_user
加入目錄 conf
- 用來放編輯好的Hadoop設定檔,而此設定檔與hadoop有關,就不再贅述
編輯一個Makefile
VERSION = 0.19.1
all: help
deb:
@dpkg-buildpackage -rfakeroot -aamd64
@dpkg-buildpackage -rfakeroot -ai386
clean:
@debian/rules clean
source:
@wget http://ftp.twaren.net/Unix/Web/apache/hadoop/core/hadoop-${VERSION}/hadoop-${VERSION}.tar.gz
@tar zxvf hadoop-${VERSION}.tar.gz -C ..
@rm conf/hadoop-env.sh
@rm conf/hadoop-site.xml
@chmod a+x `find . -name "configure"`
update:
@scp ../hadoop*_amd64.deb www.classcloud.org:/var/www/hadoop/dists/unstable/main/binary-amd64/.
@scp ../hadoop*_i386.deb www.classcloud.org:/var/www/hadoop/dists/unstable/main/binary-i386/.
@ssh www.classcloud.org /var/www/hadoop/update-repository.sh
help:
@echo "Usage:"
@echo "make deb - Build Debian Package."
@echo "make clean - Clean up Debian Package temparate files."
@echo "make source - download source tarball from hadoop mirror site."
@echo "make update - upload deb packages to classcloud.org."
@echo "make help - show Makefile options."
@echo " "
@echo "Example:"
@echo "$$ make source; make deb; make clean"
- 以上檔案做完應該會如附檔 debain-hadoop-pkg.zip
執行makefile的內容
$ make source; make deb; make clean
- 之後會在 ~/test 下出現 hadoop_0.19.1-1_amd64.deb 的檔案
參考
- Hadoop_deb製作
- 用Jazz的Hadoop打包方式
- 這篇是hadoop的deb打包過程,不過有些細節沒有寫到,因此來補完。
- 用Open Source工具開發軟體:套件包裝製作
- 這篇寫的算詳細,可以參考
前言
- 此篇要製作Nutch的deb包
- 參考前一篇 Deb檔打包工作[前一篇參考Jazz打包方法]
- 動機: Nutch 的安裝方法繁瑣,並且設定檔輸入錯誤則難以debug,常nutch執行完後才知道完全沒有抓到資料,卻又找不出問題在哪?因此若用deb包安裝完後,使用者簡單的再設定一下就可以上手。
- 目的:安裝完此Nutch包,則Nutch 安裝完成,並且載入Nutch的設定檔
- 最終目的:整合hadoop, nutch , tomcat 三個複雜的軟體
- future work: 打包順利,下一步則設計nutch的簡易設定流程,如/opt/drbl/sbin/dcs
紀錄測試步驟
- 預安裝到系統的哪個目錄很重要,事先要把檔案的配置拓樸規劃好,否則要改的檔案很多,容易錯亂
- 事先產生自己的 gpg key ,在最後產生deb檔的時候會用到 (用gui的gpa產生比較理想),產生後用gpg --list-key |grep D/可以查到私鑰的八碼編碼,如:B35CE8C3
- 似乎直接修改nutch-1.0下的conf內的檔案會被警告,因此建議不要動任何原本在nutch-1.0資料夾下的檔案,改寫在debian/nutch.postinst內
1. 找到並解壓縮 nutch-1.0.tar.gz
2. 在 nutch-1.0 資料夾執行 dh_make -f ../nutch_1.0.tar.gz
3. 將debian內的 rm *.ex *.EX dir 等檔案,並修改 rules , control
- changelog
nutch (1.0-1) unstable; urgency=low * Initial release (Closes: #nnnn) <nnnn is the bug number of your ITP> -- Wei-Yu Chen <waue0920@gmail.com> Tue, 12 May 2009 11:15:51 +0800
- compat
5
- control
Source: nutch
Section:devel
Priority: extra
Maintainer: Wei-Yu Chen <waue0920@gmail.com>
Build-Depends: debhelper (>= 5)
Standards-Version: 3.7.2
Package: nutch
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, sun-java6-jre, sun-java6-bin
Suggests: sun-java6-jdk, tomcat6
Description: Apache Nutch
.
Apache Nutch is a software that search and crawl internet.
- copyright
This package was debianized by Wei-Yu Chen <waue0920@gmail.com> on
Tue, 12 May 2009 11:15:51 +0800.
It was downloaded from <url://example.com>
Upstream Author(s):
<put author's name and email here>
<likewise for another author>
Copyright:
<Copyright (C) YYYY Name OfAuthor>
<likewise for another author>
License:
<Put the license of the package here indented by 4 spaces>
The Debian packaging is (C) 2009, Wei-Yu Chen <waue0920@gmail.com> and
is licensed under the GPL, see `/usr/share/common-licenses/GPL'.
# Please also look if there are files or directories which have a
# different copyright/license attached and list them here.
- docs
CHANGES.txt LICENSE.txt NOTICE.txt README.txt README.txt
- rules (注意此檔的dh_xxxx前為一個'tab'鍵的距離)
#!/usr/bin/make -f
export DH_VERBOSE=0
all:
install:
dh_testdir
dh_testroot
dh_install -Xlicense.txt
dh_installdocs
dh_installchangelogs
#dh_installexamples
dh_compress
dh_fixperms
dh_installdeb
dh_link
dh_gencontrol
dh_md5sums
dh_builddeb
clean:
dh_clean
binary: install
build:
binary-arch:
binary-indep:
4. 增加 nutch.[install,docs,links,postinst, postrm, prerm] 等檔
- NAME.postinst, NAME.install, NAME.postrm 等檔案的NAME 須與deb的檔名相同,如:nutch.install
- nutch.install 的目錄需對應正確
- nutch.install
conf/* etc/nutch bin opt/nutch lib opt/nutch webapps opt/nutch tomcat opt/nutch plugins opt/nutch urls opt/nutch *.jar opt/nutch *.job opt/nutch *.xml opt/nutch default.properties opt/nutch
- nutch.postrm
#!/bin/sh
echo "$1"
if [ "$1" != remove ]
then
exit 0
fi
setup_hdfsadm_user() {
if ! getent passwd hdfsadm >/dev/null; then
echo "no account found: 'hdfsadm'."
else
userdel hdfsadm
rm -rf /home/hdfsadm
rm -rf /opt/nutch
rm -rf /tmp/hadoop*
rm -rf /tmp/hsperfdata*
fi
}
setup_hdfsadm_user
- nutch.postinst
#!/bin/sh
echo "$1"
if [ "$1" != configure ]
then
exit 0
fi
show_message() {
echo "You can quickly start by following ways [in /opt/nutch/ with root privilege]:"
echo "(1) Modify the urls/urls.txt file with indicate urls, one site one line."
echo "(2) Use this instruction \"bin/nutch crawl urls -dir search -depth 4 -topN 50\" to crawl web"
echo "(3) Type \" tomcat/bin/startup.sh \" and use browser to check the result in http://localhost:8080/"
echo "Enjoy !"
}
show_message
- nutch.link
etc/nutch opt/nutch/conf
5. 在 nutch-1.0 資料夾內編輯Makefile檔
- 此檔不見得要編寫,然而編寫會有執行上得便利性
- Makefile
VERSION = 0.19.1 all: help deb: @sudo dpkg-buildpackage -rfakeroot -ai386 -k0xB35CE8C3 clean: @sudo debian/rules clean source: @chmod a+x ./bin/* help: @echo "Usage:" @echo "make deb - Build Debian Package." @echo "make clean - Clean up Debian Package temparate files." @echo "make source - download source tarball from hadoop mirror site." @echo "make help - show Makefile options." @echo " " @echo "Example:" @echo "$$ make source; make deb; make clean"
6. 執行 sudo dpkg-buildpackage -rfakeroot -k0xB35CE8C3
- 若有編寫Make,也可以執行 sudo make deb
- 打包成功後會在上層目錄找到nutch-1.0.deb的檔案,而debian/資料夾內也會多了一個nutch的資料夾,此目錄的內容就是被打包在deb檔的內容
簡介
- 本專案已移至 Google Code 專案平台
- Nutch 是目前最知名也是最好的opensource 搜尋引擎專案之一,想製作自己的客製化搜尋引擎? 用Nutch就對了! Nutch簡介
- 不過Nutch的設定繁瑣,加上還要搭配Tomcat,在入手前需要花不少時間研究如何安裝使用
- NutchEz 顧名思義就是Nutch Easy,只要安裝NutchEz後就,再加上幾個指令,就可以輕鬆的產生出你自己的搜尋引擎囉!
- 若有任何問題歡迎寫信與我們聯絡
單位 作者 國家高速網路中心-格網技術組 Wei-Yu Chen waue @ nchc.org.tw
適用平台
- Ubuntu ( 8.04 up)
- Debian ( 5.0 up)
安裝方法
方法一(圖形介面):
方法二(文字介面):
- 在 console 端,執行以下命令:
# 32位元請下載 $ wget http://trac.nchc.org.tw/cloud/export/107/package/nutchez_0.1-3_i386.deb # 64位元請下載 $ wget http://trac.nchc.org.tw/cloud/export/107/package/nutchez_0.1-3_amd64.deb
然後執行
$ sudo dpkg -i nutchez_0.1-*.deb
使用方法
- 0. 輸入指令nutchez
$ nutchez
- 1. 中文版的主選單
- 2-1. 輸入或修改你要爬取的網址,一行一個網址
- 2-2. 輸入你搜尋機器人的名字
- 2-3. 輸入你要的收尋深度 ( 以http://www.nchc.org.tw/tw/為例,當深度為2,就能抓取上千個網址)
- 2-4. 輸入你的搜尋網頁所要用的port (當8080 port已被佔用的時候,請輸入其他port)
- 2-5. 是否清除上次的搜尋,第一次使用不會出現
- 2-6. 確認以上輸入的資訊是否正確,正確請按"ok",不正確的話選擇"reset",跳出程式可以選擇"exit"
- 2-7. 當前一步驟按了ok後,程式開始執行
- 2-7.1. 若2-5選擇要清除上次的搜尋結果,則會提醒使用者,資料夾被更名
- 2-8. 運作完成後,自動開啟瀏覽器到 http://localhost:8080
- 2-9. Enjoy NutchEz !
- 3-1. 若選擇 管理NutchEz的網頁伺服器 !
- 3-2. 程式會自動偵測是否有開啟,只要選擇要不要開啟或要不要關閉即可 !
2009/09/01 news ! bug fixed
- 問題:
- 安裝nutchez後執行 nutchez會出現以下錯誤
> /usr/bin/nutchez: line 58: [: too many arguments > /usr/bin/nutchez: line 92: [: too many arguments
- 安裝nutchez後執行 nutchez會出現以下錯誤
- 解決:
- 因為有相依套件 dialog 沒有安裝,目前提供的 nutchez 新版 deb 檔已修正這個問題。之前下載過的使用者可以手動安裝 dialog 套件便得以解決。
~$ sudo apt-get install dialog
- 因為有相依套件 dialog 沒有安裝,目前提供的 nutchez 新版 deb 檔已修正這個問題。之前下載過的使用者可以手動安裝 dialog 套件便得以解決。
2009 07 08 新增功能
- 有主選單以提供開啟或關閉Tomcat
- 中文顯示
- 選擇是否不繼續上次的搜尋內容
- 工作目錄結構較為簡潔
- 新增 README file
參考
前言
- 現在下載的檔案還是叫做nutch,等之後調整較多並加入ui再改名
動機
- 簡化Nutch的安裝操作流程
- 透過此專案學習deb打包, perl, python, dialog, 以及程式流程設計
版本控制
- 下載 nutchEz 專案
$ cd $workDir $ svn co https://trac.nchc.org.tw/svn/cloud/
- 專案更新
$ svn update $ svn ci
工作項目
- rpm包
- 於gui內設定
- 中英文選單
- 加入/刪除抓取網址
- 深度
- 調整tomcat port
- 精簡體積
- 瀏覽人數與下載人數網頁
- 加入depth選四以上的要三思而後行阿@@
- nutchez
#!/bin/bash # Author: WeiYu Chen <waue _at_ nchc org tw> # License: GPL # Description: Eazily use for Nutch # . NUTCHEZ_SCRIPT_PATH="${NUTCHEZ_SCRIPT_PATH:-/opt/nutch}" . ./nutchez-func.sh # root ? #check_if_root # show url lists CHECK=0 while [ $CHECK -eq 0 ]; do LOCK=1 while [ $LOCK -eq 1 ]; do # milestone M1 show_urls URL=$? echo_vb "$URL" # add or delete url: ok , exit # ok =0 , exit =1 if [ $URL -eq 0 ];then # go_to_M2 LOCK=0 else #return_console exit fi done # milestone M2 # setup search engine personality # next, back setup_robot # setup the crawl paramater # next, back setup_crawler # setup the tomcat paramater # next, back setup_tomcat # show the final checklist final_confirm FC=$? echo_vb $FC # START , back, cancel # start =0 , back =1 if [ $FC -eq 0 ];then #go_to_M3 CHECK=1 else #go_to_M1 LOCK=1 CHECK=0 #return_console fi done start_crawl start_tomcat # show result message show_report # Done
- nutchez-func.sh
#!/bin/bash # Author: WeiYu Chen <waue _at_ nchc org tw> # License: GPL # Description: Eazily use for Nutch # . . $NUTCHEZ_SCRIPT_PATH/conf/hadoop-env.sh VERB=1 #DIALOG=dialog #NEZ_DIR=/home/waue/.nutchez #NEZ_DIR_URL #NEZ_DIR_OTHER echo_vb () { if [ $VERB -eq 1 ]; then echo $1 fi } test_file () { if ! test -e $1 ; then echo "" > $1 fi } check_if_root() { if [ ! "$UID" = "0" ]; then echo_vb "[$LOGNAME] You need to run this script \"`basename $0`\" as root." exit 1 fi } show_urls (){ echo_vb "show urls : ok =0 ,cancel = 1" test_file ~/n.url.txt # dialog begin dialog --editbox ~/n.url.txt 30 50 2> ~/n.url.tmp return $? } setup_robot () { test_file ~/n.robot.txt echo_vb "setup_robot" # dialog dialog --inputbox "this agent name \n ex: nutch" 0 0 2> ~/n.robot.tmp } setup_crawler () { echo_vb "setup_crawler" test_file ~/n.crawler.txt dialog --inputbox "Depth \n ex: 5" 0 0 2> ~/n.crawler.tmp } setup_tomcat () { echo_vb "setup_tomcat" test_file ~/n.tomcat.txt dialog --inputbox "explorer port \n ex:8080 " 0 0 2> ~/n.tomcat.tmp } final_confirm () { echo_vb "final_confirm : start =0 , back =1 " MSG="urls = \n `cat ~/n.url.txt` \n robot name = \n `~/n.robot.tmp` \n depth = \n `~/n.crawler.tmp` \n explorer port = \n `cat ~/n.tomcat.tmp` \n" #read READ dialog --msgbox "$MSG" 0 0 return $READ } start_crawl () { echo_vb "start_crawl" } start_tomcat () { echo_vb "start_tomcat " } show_report () { echo_vb "show_report " }
講師阿碩寫得教學
投影片
我的 Google Engine Applications 總覽
留言板範例
範例1
範例2
範例3
範例4
範例5
nutchez-dev 開發
- comeon dialog 如何存變數等問題?
請看 /usr/share/doc/dialog/example 的範例
- dialog 常回傳 255 ?
注意shell裡面 dialog --msgbox $MSG 0 0 2>/tmp/file 如此寫容易錯,應該改成 dialog --msgbox "$MSG" 0 0 2>/tmp/file
- editbox 載入檔案內容總是空白
注意shell裡面 dialog --editbox "$file" 0 0 2>"$file" 則每次載入檔案都是空的,應該改成 dialog --editbox "$file" 0 0 2>"$file1"
- "" 的訣竅
在 "" 中,可以用變數 echo "The Message = $MSG " 或執行符號``如 echo "The File content = `cat $file`"
版本控制
- 下載 nutchEz 專案
$ cd $workDir $ svn co https://trac.nchc.org.tw/svn/cloud/
- 上傳專案
- $workDir 是你放svn的目錄,如/opt/cloud
- $yourProjectDir 是你要上傳的專案,原本可能放在$oripath內,請svn co完後移到$wordDir目錄,在進行svn add, svn ci
$ cd $workDir $ svn co https://trac.nchc.org.tw/svn/cloud/ $ mv $oripath/$yourProjectDir ./ $ svn add $yourProjectDir $ svn ci $ ln -sf $workDir/$yourProjectDir
- 專案更新(僅內容更改)
$ svn update $ svn ci
- 專案更新(有檔案新增)
$ svn update $ svn add newFile $ svn ci
- 用shell 批次改檔名
- 此用法應用到 for in , 正規表示法, awk , sed 因此還學滿多的
#!/bin/sh cd ~/test2 echo `pwd` for i in *.[tT][iI][fF]; do # 防止有個檔案叫做*.[tT][iI][fF] if [ "$i" != "*.[tT][iI][fF]" ]; then #取得副檔名 subname="`echo $i | awk -F '.' '{print $NF}'`" #取得主檔名 filename="`echo $i | sed -e s/\.${subname}//`" #將 .tif 轉成 .pdf #tiff2pdf -o "${filename}.pdf" "$i" echo "${filename}.${subname} -> ${filename}.pdf" cp ${filename}.${subname} ${filename}.pdf #若執行成功則刪除 .tif 檔案 if [ $? -eq 0 ]; then rm -rf $i fi fi done
- 此用法應用到 for in , 正規表示法, awk , sed 因此還學滿多的
- awk
- -F 指定分隔字元為何
- 內可表明要執行的script
- 最後的欄位填入檔案,若 指令 |awd
Examples: gawk '{ sum += $1 }; END { print sum }' file gawk -F: '{ print $1 }' /etc/passwd
- sed
Usage: sed [OPTION]... {script-only-if-no-other-script} [input-file]... -n, --quiet, --silent suppress automatic printing of pattern space -e script, --expression=script add the script to the commands to be executed
* 正規表示法
* [aA]oo 代表 aoo 或 Aoo
* [a-z]o 代表 ao, or bo,...或zo
* [^a-z]oo 代表 不要有 aoo, .... 或zoo,
* ^the 代表該行開頭為 the的字
* ^[^a-zA-Z] 代表 行首不要有a或A-Z的字
* \.$ 代表 行尾為.的行
* ^$ 代表無字元的行
* g.*g 代表 任何頭尾為g的字串,包含gg,goog等
* g.+g 代表 任何頭尾為g且中間不為空的字,如gog,但不包含gg
* g.?g 代表 任何頭尾有g但中間只有一個或0個字元的字,包含gg,gog, 不包含goog等
* o\{2\} 代表出現oo的字串 (\為跳脫字元,否則會被shell給解析成另外的意思)
* a|b 代表 a 或 b
* A(xyz)+C 代表 字串如 AxyzxyzxyzxyzC 但不包含AC ,"(" 與 ")" 代表群組的意思
NutchEz 0.1
- NutchEz 0.1 程式大致完工
- 目前只差測試&Debug
nutchEz-0.1 dev
首次:初步測試成功
- 可直接用gui設定nutch,並且打開瀏覽器查詢收尋結果
內容
- 可支援多使用者使用
- 因此不可僅限root才能使用
- 設定檔也不能單純用/etc/nutch下的檔案
- 解決tomcat設定問題
- tomcat 原本放在/opt/nutch/下,但此目錄為特權目錄,修改裡面內容要動用特權指令,不用又無法更改tomcat port、及nutch-site.xml的path
- 引入並修改Hadoop的環境變數,否則nutch只認得/opt/nutch/conf內的設定檔
- 不斷的debug及改流程
未來工作
- 打包 (內有.svn檔是否有關係?) 後,再安裝此檔重新測試
- 除錯訊息的說明
- 輸入訊息的說明
- 中英文選單
- 中控台選單
- NUTCH的更細節設定
心得
- depth = 4 的設定,讓電腦跑好久,下次還是維持3,但多加個網址,應該比較好
hadoop.nchc 計算平台 復原方法:
(11時42分58秒) 阿聰: back to live (11時43分08秒) 阿聰: hadoop.nchc.org.tw is back to live (11時43分21秒) 阿聰: 不太懂原因 (11時44分01秒) 阿聰: 不過我的做法是把 name/current 底下的 VERSION 跟 fsimage (11時44分04秒) 阿聰: 備份起來 (11時44分58秒) 阿聰: 然後把 /var/lib/hadoop/cache/hadoop/dfs 底下的 name 目錄砍掉 (11時45分16秒) 阿聰: 從新跑 sudo su -s /bin/sh hadoop -c "hadoop namenode -format" (11時45分34秒) 阿聰: 再把 VERSION 跟 VERSION (11時45分41秒) 阿聰: fsimage (11時45分44秒) 阿聰: 拷回去 (11時47分06秒) 阿聰: 目前看起來資料是都正常啦 (11時47分14秒) 阿聰: 沒有不見
nutchez-dev 進度
- 可以運作爬網
- tomcat 整合有問題,無法開啟指定的port
- 修正些小bug
- url.txt 檔內的url 必須灌上 http:// 字樣
- 爬網時有些java的錯誤產生
hadoop.nchc.org.tw 平台的需求
- 硬碟 500G 全上
- library -> 0.19.1
nutchez 目前進度
- 目前的版本 nutchez_0.1 已經可以順暢的運作
- menu --> ok
- crawl web --> ok
- tomcat --> ok
- multi-user --> ok
增加功能
- 判斷中英文,模式:初學者(較多說明)、使用者(快速設定使用)、除錯(細部訊息)
- 說明資訊
- nutch-site.xml的更多設定
需改進
- 搜尋第二次就會超久
- 猜測是繼承第一次的網址繼續爬網
- 加個選項:承續前一次or重新爬網
- 加個選項:只爬固定網址下的網頁
- 在搜尋的時候會有些java的error
- 鎖定只爬取某些網頁
- 減肥
- nutch = 80M , tomcat = 40M , total => 120M , 每個使用者又把tomcat複製到自己的家目錄下
- 用link的方式,執行檔都用/opt/nutch/tomcat 但/opt/nutch/tomcat/conf 用自己家目錄的設定
Nutch 研究與隨筆
前言
- 目前開發NutchEz 已經可以運作了,但都是基本功能,也找出某些問題
- 希望在完整的看完Nutch的官方網頁後,得到更好的靈感與改進方式
更多指令
readdb
- read / dump crawl db
- Usage: CrawlDbReader <crawldb> (-stats | -dump <out_dir> | -topN <nnnn> <out_dir> [<min>] | -url <url>)
- -stats [-sort] print overall statistics to System.out
$ nutch readdb /tmp/search/crawldb -stats 09/06/09 12:18:13 INFO mapred.MapTask: data buffer = 79691776/99614720 09/06/09 12:18:13 INFO mapred.MapTask: record buffer = 262144/327680 09/06/09 12:18:14 INFO crawl.CrawlDbReader: TOTAL urls: 1072 09/06/09 12:18:14 INFO crawl.CrawlDbReader: status 1 (db_unfetched): 1002 09/06/09 12:18:14 INFO crawl.CrawlDbReader: status 2 (db_fetched): 68
- -dump <out_dir> [-format normal|csv ] dump the whole db to a text file in <out_dir>
$ nutch readdb /tmp/search/crawldb/ -dump ./dump $ vim ./dump/part-00000
- -url <url> print information on <url> to System.out
$ nutch readdb /tmp/search/crawldb/ -url http://www.nchc.org.tw/tw/ URL: http://www.nchc.org.tw/tw/ Version: 7 Status: 6 (db_notmodified) Fetch time: Thu Jul 09 14:34:48 CST 2009 Modified time: Thu Jan 01 08:00:00 CST 1970 Retries since fetch: 0 Retry interval: 2592000 seconds (30 days) Score: 3.1152809 Signature: ce0202bbd593b09b86ce8a9aa991b321 Metadata: _pst_: success(1), lastModified=0 $ nutch readdb /tmp/search/crawldb/ -url http://www.nchc.org.tw URL: http://www.nchc.org.tw not found
- -topN <nnnn> <out_dir> [<min>] dump top <nnnn> urls sorted by score to <out_dir>
inject
- inject new urls into the database
- Usage: Injector <crawldb> <url_dir>
readlinkdb
- read / dump link db
- Usage: LinkDbReader <linkdb> {-dump <out_dir> | -url <url>)
$ nutch readlinkdb /tmp/search/linkdb/ -dump ./dump $ vim ./dump/part-00000
readseg
- read / dump segment data
- Usage: SegmentReader (-dump ... | -list ... | -get ...) [general options]
- SegmentReader -dump <segment_dir> <output> [general options]
$ nutch readseg -dump /tmp/search/segments/20090609143444/ ./dump/ $ vim ./dump/dump
- SegmentReader -list (<segment_dir1> ... | -dir <segments>) [general options]
$ nutch readseg -list /tmp/search/segments/20090609143444/ NAME GENERATED FETCHER START FETCHER END FETCHED PARSED 20090609143444 1 2009-06-09T14:34:48 2009-06-09T14:34:48 1 1
- SegmentReader -get <segment_dir> <keyValue> [general options]
$ nutch readseg -get /tmp/search/segments/20090609143444/ http://bioinfo.nchc.org.tw/
updatedb
- update crawl db from segments after fetching
- Usage: CrawlDb <crawldb> (-dir <segments> | <seg1> <seg2> ...) [-force] [-normalize] [-filter] [-noAdditions]
$ nutch updatedb /tmp/search/crawldb/ -dir /tmp/search/segments/
dedup
- remove duplicates from a set of segment indexes
- Usage: DeleteDuplicates <indexes> ...
$ nutch dedup /tmp/search/indexes/
筆記
Linux技巧:使用screen管理console命令
動機
- 當遠端登入時,執行命令到一半,不想等了,中斷掉登入的連線,比如說關掉putty或ssh,執行到一半的程序還會跑嗎? ...顯然,答案是:不會!
- 如果我在學校電腦連入一個bbs,沒有斷線後回家用家裡電腦遠端連線到學校該電腦,此時還能看到bbs的畫面嗎?.. 顯然答案還是:不會
- 還有當遠端登入一台機器後,如果需要在視窗內常常查閱數個程序的資訊,比方我要編輯一個abc.sh,編輯時想馬上執行這個abc.sh這隻程式,同時還要執行top觀看系統狀態。如此一來,傳統的作法是,開三個視窗每個視窗都各進行登入程序到主機。但隨後又想看開的port,或不想離開該命令,卻想執行其他指令時,是否又要再新增一個登入的連線,不斷的輸入帳號密碼!
用screen 可以解決上面的問題
- 使用screen可以解決SIGHUP問題
- 利用screen這種功能來管理你的遠程會話,保存你所有的工作內容。
範例演練
定義: C-a :=> Ctrl+ a
- 用screen 開啟一個場景,中間離開後,利用-ls查看編號名稱,再用-r 回到場景
$ screen vi /tmp/abc $ C-a d [detached] $ screen -ls There is a screen on: 11720.pts-4.vpro (Detached) 1 Socket in /var/run/screen/S-waue. $ screen -r 11720
- -dmS可以在背景產生一個被命名的場景,場景編號就是pid,因此可以用kill -9 來刪除,而被刪除的場景,會成線removed狀態,可以透過-wipe清除
$ screen -dmS mygdb gdb execlp_test $ screen -dmS mytest $ screen -ls There are screens on: 11897.mytest (Detached) 11889.mygdb (Detached) 11720.pts-4.vpro (Detached) $ kill -9 11889 $ screen -ls There are screens on: 11897.mytest (Detached) 11889.mygdb (Dead ???) 11720.pts-4.vpro (Detached) $ screen -ls There are screens on: 11897.mytest (Detached) 11720.pts-4.vpro (Detached)
進入screen 後的控制命令
- 執行screen 就可以進入screen 的世界了
$ screen
- screen 用法
Use: screen [-opts] [cmd [args]]
- 以下為常用的 -opts
-c file 使用配置文件file,而不使用默認的$HOME/.screenrc -d 不開啟新的screen會話,而是斷開其他正在運行的screen會話 -h num 指定歷史回滾緩衝區大小為num行 -ls 列出現有screen會話,格式為pid.tty.host -d 啟動一個開始就處於斷開模式的會話 -S sessionname 創建screen會話時為會話指定一個名字 -v 顯示screen版本信息 -wipe [match] 同-list,但刪掉那些無法連接的會話
進入screen內的開啟,關閉,切換
- 我們可以在console開啟許多場景,這個場景的列表可以用以下指令來查看有幾個場景
$ screen -ls
- 每個場景又可以開許多視窗,以下就是開啟、關閉、切換、列出 視窗的方法
C-a c 或 C-a C-c 開啟新的視窗,並同時切換到這個新的視窗 C-a n 或 C-a C-n 或 C-a (space) 切換到下一個視窗(0->1 1->2 ...) C-a p 或 C-a C-p 切換到上一個視窗(1->0 2->1 ...) C-a C-a 切換到上一個顯示過的視窗(不是照順序切換) C-a 0 切換到第 0 個視窗 C-a (1..9) 切換到第 (1..9) 個視窗 C-a w 或 C-a C-w 會列出目前所開啟的視窗 C-a k 關閉此視窗並換到上一個視窗 C-a ' 或 C-a " 會出現 "Switch to window:" 字樣,輸入號碼後就可切到該視窗
進入screen內的單一視窗使用中的指令
C-a d 脫離(detach)目前的 screen ,並放到背景執行 C-a H 紀錄目前視窗所有顯示過的東西(檔名為 screenlog.n n 為視窗號碼) C-a i 顯示目前視窗的資訊 C-a l 重繪視窗,如果有字顯示亂掉了可以用這個指令 C-a m 可以顯示最近一次顯示過的訊息 C-a t 或 C-a C-t 顯示系統的時間及主機名稱還有負載 C-a v 顯示版本資訊 C-a x 視窗保護鎖定 C-a ? 線上求助畫面
進入screen內的複製/捲軸 模式
按下 C-a [ 就可以進入 複製/捲軸 模式(只有在目前視窗才算,其他視窗照常)基本上跟 vi 很像:
h, j, k, l 分別為向左,向下,向上,向右移動一格(或是一行) 0 移到該行最左邊 與 $ 分別移到該行最左邊及最右邊的非空白字元 w 以字為單位往前移動並移到字首 b 以字為單位往後移動並移到字首 e 以字為單位往前移動並移到字尾 C-b 向上捲一頁 C-f 向下捲一頁 C-u 向上捲半頁 C-u 向下捲半頁 / 與 ? 向下或向上尋找字串 (space) 第一次按下到第二次按下的區域會被複製到暫存區內 (ESC) 離開 複製/捲軸 模式
References
整理ICAS 程式
- 升級成hadoop0.20.0版
- 撰寫在vm上以方便分享
- 將eclipse的設定盡量完整
- eclipse mapreduce plugin
- java doc , hadoop doc
- hadoop src
- class , run 設定
- eclipse 的hadoop-*-{core,ant,tools}.jar 這三個包的
- src
$HADOOP_HOME/src
- javadoc
$HADOOP_HOME/docs/api
- 其實在這裡可以找到很多範例程式:
$HADOOP_HOME/src/examples/org/apache/hadoop/examples/
hadoop 0.20 的重大改變
- 原本的 hadoop-site.xml 與 hadoop-default.xml 都不見了
*-site.xml
- 放在 $hadoop_conf_dir 內就會被載入
core-site.xml
<configuration>
<property>
<name>fs.default.name</name>
<value>hdfs://localhost:9000</value>
</property>
</configuration>
hdfs-site.xml
<configuration>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
</configuration>
mapred-site.xml
<configuration>
<property>
<name>mapred.job.tracker</name>
<value>localhost:9001</value>
</property>
</configuration>
*-default.xml
- 詳細的設定,被放置於src 資料夾內
- 將 *-default.xml檔案與*-site.xml 放在一起就會載入其內部的設定值
- 此程式說明載入設定動作:/opt/hadoop/src/core/org/apache/hadoop/conf/Configuration.java
core-default.xml
- /opt/hadoop/src/core
hdfs-default.xml
- /opt/hadoop/src/hdfs
mapred-default.xml
- /opt/hadoop/src/mapred
零. 前言
- 開發hadoop 需要用到許多的物件導向語法,包括繼承關係、介面類別,而且需要匯入正確的classpath,否則寫hadoop程式只是打字練習...
- 用類 vim 來處理這種複雜的程式,有可能會變成一場惡夢,因此用eclipse開發,搭配mapreduce-plugin會事半功倍。
- 早在hadoop 0.19~0.16之間的版本,筆者就試過各個plugin,每個版本的plugin都確實有大大小小的問題,如:hadoop plugin 無法正確使用、無法run as mapreduce。hadoop0.16搭配IBM的hadoop_plugin 可以提供完整的功能,但是,老兵不死,只是凋零...
- 子曰:"逝者如斯夫,不捨晝夜",以前寫的文件也落伍了,要跟上潮流,因此此篇的重點在:用eclipse 3.4.2 開發hadoop 0.20程式,並且測試撰寫的程式運作在hadoop平台上
- 以下是我的作法,如果你有更好的作法,或有需要更正的地方,請與我聯絡
單位 作者 國家高速網路中心-格網技術組 Wei-Yu Chen waue @ nchc.org.tw
0.0 Info Update
- Last Update: 2010/01/22
最新版本的 Eclipse 3.5 搭配 Ubuntu 9.04 + hadoop-eclipse-plugin 0.20.1 ,初步測試功能皆可正常運作
但 Ubuntu 9.10 的 各版本 Eclipse , 似乎會有 gtk 圖形介面的bug ,有此一說增加 GDK_NATIVE_WINDOWS=1 就可以解決問題,但經過初步測試似乎無用
0.1 環境說明
- ubuntu 8.10
- sun-java-6
- eclipse 3.4.2
- hadoop 0.20.0
0.2 目錄說明
- 使用者:waue
- 使用者家目錄: /home/waue
- 專案目錄 : /home/waue/workspace
- hadoop目錄: /opt/hadoop
一、安裝
安裝的部份沒必要都一模一樣,僅提供參考,反正只要安裝好java , hadoop , eclipse,並清楚自己的路徑就可以了
1.1. 安裝java
首先安裝java 基本套件
$ sudo apt-get install java-common sun-java6-bin sun-java6-jdk sun-java6-jre
1.1.1. 安裝sun-java6-doc
1 將javadoc (jdk-6u10-docs.zip) 下載下來 下載點
2 下載完後將檔案放在 /tmp/ 下
3 執行
$ sudo apt-get install sun-java6-doc
1.2. ssh 安裝設定
$ apt-get install ssh $ ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa $ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys $ ssh localhost
執行ssh localhost 沒有出現詢問密碼的訊息則無誤
1.3. 安裝hadoop
安裝hadoop0.20到/opt/並取目錄名為hadoop
$ cd ~ $ wget http://apache.ntu.edu.tw/hadoop/core/hadoop-0.20.0/hadoop-0.20.0.tar.gz $ tar zxvf hadoop-0.20.0.tar.gz $ sudo mv hadoop-0.20.0 /opt/ $ sudo chown -R waue:waue /opt/hadoop-0.20.0 $ sudo ln -sf /opt/hadoop-0.20.0 /opt/hadoop
- 編輯 /opt/hadoop/conf/hadoop-env.sh
export JAVA_HOME=/usr/lib/jvm/java-6-sun export HADOOP_HOME=/opt/hadoop export PATH=$PATH:/opt/hadoop/bin
- 編輯 /opt/hadoop/conf/core-site.xml
<configuration>
<property>
<name>fs.default.name</name>
<value>hdfs://localhost:9000</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/tmp/hadoop/hadoop-${user.name}</value>
</property>
</configuration>
- 編輯 /opt/hadoop/conf/hdfs-site.xml
<configuration>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
</configuration>
- 編輯 /opt/hadoop/conf/mapred-site.xml
<configuration>
<property>
<name>mapred.job.tracker</name>
<value>localhost:9001</value>
</property>
</configuration>
- 啟動
$ cd /opt/hadoop $ source /opt/hadoop/conf/hadoop-env.sh $ hadoop namenode -format $ start-all.sh $ hadoop fs -put conf input $ hadoop fs -ls
- 沒有錯誤訊息則代表無誤
1.4. 安裝eclipse
- 在此提供兩個方法來下載檔案
- 方法一:下載 eclipse SDK 3.4.2 Classic,並且放這檔案到家目錄
- 方法二:貼上指令
$ cd ~ $ wget http://ftp.cs.pu.edu.tw/pub/eclipse/eclipse/downloads/drops/R-3.4.2-200902111700/eclipse-SDK-3.4.2-linux-gtk.tar.gz
- eclipse 檔已下載到家目錄後,執行下面指令:
$ cd ~ $ tar -zxvf eclipse-SDK-3.4.2-linux-gtk.tar.gz $ sudo mv eclipse /opt $ sudo ln -sf /opt/eclipse/eclipse /usr/local/bin/
二、 建立專案
2.1 安裝hadoop 的 eclipse plugin
- 匯入hadoop 0.20.0 eclipse plugin
$ cd /opt/hadoop $ sudo cp /opt/hadoop/contrib/eclipse-plugin/hadoop-0.20.0-eclipse-plugin.jar /opt/eclipse/plugins
$ sudo vim /opt/eclipse/eclipse.ini
- 可斟酌參考eclipse.ini內容(非必要)
-startup plugins/org.eclipse.equinox.launcher_1.0.101.R34x_v20081125.jar --launcher.library plugins/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805 -showsplash org.eclipse.platform --launcher.XXMaxPermSize 512m -vmargs -Xms40m -Xmx512m
2.2 開啟eclipse
- 打開eclipse
$ eclipse &
一開始會出現問你要將工作目錄放在哪裡:在這我們用預設值
PS: 之後的說明則是在eclipse 上的介面操作
2.3 選擇視野
| window -> | open pers.. -> | other.. -> | map/reduce |
設定要用 Map/Reduce? 的視野
使用 Map/Reduce? 的視野後的介面呈現
2.4 建立專案
file -> new -> project -> Map/Reduce? -> Map/Reduce? Project -> next
建立mapreduce專案(1)
建立mapreduce專案的(2)
project name-> 輸入 : icas (隨意) use default hadoop -> Configur Hadoop install... -> 輸入: "/opt/hadoop" -> ok Finish
2.5 設定專案
由於剛剛建立了icas這個專案,因此eclipse已經建立了新的專案,出現在左邊視窗,右鍵點選該資料夾,並選properties
Step1. 右鍵點選project的properties做細部設定
Step2. 進入專案的細部設定頁
- java Build Path -> Libraries -> hadoop-0.20.0-ant.jar
- java Build Path -> Libraries -> hadoop-0.20.0-core.jar
- java Build Path -> Libraries -> hadoop-0.20.0-tools.jar
- 以 hadoop-0.20.0-core.jar 的設定內容如下,其他依此類推
source ...-> 輸入:/opt/opt/hadoop-0.20.0/src
javadoc ...-> 輸入:file:/opt/hadoop/docs/api/
Step3. hadoop的javadoc的設定完後(2)
Step4. java本身的javadoc的設定(3)
- javadoc location -> 輸入:file:/usr/lib/jvm/java-6-sun/docs/api/
設定完後回到eclipse 主視窗
2.6 連接hadoop server
Step1. 視窗右下角黃色大象圖示"Map/Reduce? Locations tag" -> 點選齒輪右邊的藍色大象圖示:
Step2. 進行eclipse 與 hadoop 間的設定(2)
Location Name -> 輸入:hadoop (隨意) Map/Reduce Master -> Host-> 輸入:localhost Map/Reduce Master -> Port-> 輸入:9001 DFS Master -> Host-> 輸入:9000 Finish
設定完後,可以看到下方多了一隻藍色大象,左方展開資料夾也可以秀出在hdfs內的檔案結構
三、 撰寫範例程式
- 之前在eclipse上已經開了個專案icas,因此這個目錄在:
- /home/waue/workspace/icas
- 在這個目錄內有兩個資料夾:
- src : 用來裝程式原始碼
- bin : 用來裝編譯後的class檔
- 如此一來原始碼和編譯檔就不會混在一起,對之後產生jar檔會很有幫助
- 在這我們編輯一個範例程式 : WordCount
3.1 mapper.java
- new
File -> new -> mapper
- create
source folder-> 輸入: icas/src
Package : Sample
Name -> : mapper
- modify
package Sample; import java.io.IOException; import java.util.StringTokenizer; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Mapper; public class mapper extends Mapper<Object, Text, Text, IntWritable> { private final static IntWritable one = new IntWritable(1); private Text word = new Text(); public void map(Object key, Text value, Context context) throws IOException, InterruptedException { StringTokenizer itr = new StringTokenizer(value.toString()); while (itr.hasMoreTokens()) { word.set(itr.nextToken()); context.write(word, one); } } }
3.2 reducer.java
- new
- File -> new -> reducer
- create
source folder-> 輸入: icas/src
Package : Sample
Name -> : reducer
- modify
package Sample; import java.io.IOException; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Reducer; public class reducer extends Reducer<Text, IntWritable, Text, IntWritable> { private IntWritable result = new IntWritable(); public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException { int sum = 0; for (IntWritable val : values) { sum += val.get(); } result.set(sum); context.write(key, result); } }
- File -> new -> Map/Reduce? Driver
3.3 WordCount.java (main function)
- new
建立WordCount.java,此檔用來驅動mapper 與 reducer,因此選擇 Map/Reduce? Driver
- create
source folder-> 輸入: icas/src
Package : Sample
Name -> : WordCount.java
- modify
package Sample; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Job; import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; import org.apache.hadoop.util.GenericOptionsParser; public class WordCount { public static void main(String[] args) throws Exception { Configuration conf = new Configuration(); String[] otherArgs = new GenericOptionsParser(conf, args) .getRemainingArgs(); if (otherArgs.length != 2) { System.err.println("Usage: wordcount <in> <out>"); System.exit(2); } Job job = new Job(conf, "word count"); job.setJarByClass(WordCount.class); job.setMapperClass(mapper.class); job.setCombinerClass(reducer.class); job.setReducerClass(reducer.class); job.setOutputKeyClass(Text.class); job.setOutputValueClass(IntWritable.class); FileInputFormat.addInputPath(job, new Path(otherArgs[0])); FileOutputFormat.setOutputPath(job, new Path(otherArgs[1])); System.exit(job.waitForCompletion(true) ? 0 : 1); } }
- 三個檔都存檔後,可以看到icas專案下的src,bin都有檔案產生,我們用指令來check
$ cd workspace/icas $ ls src/Sample/ mapper.java reducer.java WordCount.java $ ls bin/Sample/ mapper.class reducer.class WordCount.class
四、測試範例程式
- 由於hadoop 0.20 此版本的eclipse-plugin依舊不完整 ,如:
- 右鍵點選WordCount.java -> run as -> run on Hadoop :沒有效果
- 因此,4.1 提供一個eclipse 上解除 run-on-hadoop 封印的方法。而4.2 則是避開run-on-hadoop 這個功能,用command mode端指令的方法執行。
4.1 解除run-on-hadoop封印
有一熱心的hadoop使用者提供一個能讓 run-on-hadoop 這個功能恢復的方法。
原因是hadoop 的 eclipse-plugin 也許是用eclipse europa 這個版本開發的,而eclipse 的各版本 3.2 , 3.3, 3.4 間也都有或多或少的差異性存在。
因此如果先用eclipse europa 來建立一個新專案,之後把europa的eclipse這個版本關掉,換用eclipse 3.4開啟,之後這個專案就能用run-on-mapreduce 這個功能囉!
有興趣的話可以試試!(感謝逢甲資工所謝同學)
4.2 運用終端指令
4.2.1 產生Makefile 檔
$ cd /home/waue/workspace/icas/ $ gedit Makefile
- 輸入以下Makefile的內容
JarFile="sample-0.1.jar" MainFunc="Sample.WordCount" LocalOutDir="/tmp/output" all:help jar: jar -cvf ${JarFile} -C bin/ . run: hadoop jar ${JarFile} ${MainFunc} input output clean: hadoop fs -rmr output output: rm -rf ${LocalOutDir} hadoop fs -get output ${LocalOutDir} gedit ${LocalOutDir}/part-r-00000 & help: @echo "Usage:" @echo " make jar - Build Jar File." @echo " make clean - Clean up Output directory on HDFS." @echo " make run - Run your MapReduce code on Hadoop." @echo " make output - Download and show output file" @echo " make help - Show Makefile options." @echo " " @echo "Example:" @echo " make jar; make run; make output; make clean"
4.2.2 執行
- 執行Makefile,可以到該目錄下,執行make [參數],若不知道參數為何,可以打make 或 make help
- make 的用法說明
$ cd /home/waue/workspace/icas/ $ make Usage: make jar - Build Jar File. make clean - Clean up Output directory on HDFS. make run - Run your MapReduce code on Hadoop. make output - Download and show output file make help - Show Makefile options. Example: make jar; make run; make output; make clean
- 下面提供各種make 的參數
make jar
- 1. 編譯產生jar檔
$ make jar
make run
- 2. 跑我們的wordcount 於hadoop上
$ make run
- make run基本上能正確無誤的運作到結束,因此代表我們在eclipse編譯的程式可以順利在hadoop0.20的平台上運行。
- 而回到eclipse視窗,我們可以看到下方視窗run完的job會呈現出來;左方視窗也多出output資料夾,part-r-00000就是我們的結果檔
- 因為有設定完整的javadoc, 因此可以得到詳細的解說與輔助
make output
- 3. 這個指令是幫助使用者將結果檔從hdfs下載到local端,並且用gedit來開啟你的結果檔
$ make output
make clean
- 4. 這個指令用來把hdfs上的output資料夾清除。如果你還想要在跑一次make run,請先執行make clean,否則hadoop會告訴你,output資料夾已經存在,而拒絕工作喔!
$ make clean
五、結論
- 搭配eclipse ,我們可以更有效率的開發hadoop
- hadoop 0.20 與之前的版本api以及設定都有些改變,因此hadoop 環境的設定,需要看 hadoop 0.20 的quickstart; 而如何使用 hadoop 0.20 的api,則可以看 /opt/hadoop/src/example/ 裡面的程式碼來提供初步的構想
- 前幾天在想把程式改成hadoop0.20版,已應付時代潮流
- 但是剛剛測了一下,hadoop0.20的程式沒辦法跑在實驗主機cloudera-0.18.3上
- 如果不能跑在測試主機上面,下個月底沒辦法在上面demo可能會遭殃
- 還是回頭搞hadoop0.18.3, 驀然回首,0.18.3 依舊在燈火闌珊處 (煙)
Makefile 教學
上手
教學
完整樣板
官方手冊
2009-06-25
- 新加坡 SIG on Hadoop 視訊演講
- 時間:2009-06-25 18:00-19:00 (GMT+8) Taiwan/Singapore?
- 講題:Building ICAS with Hadoop and HBase
- Q: How many people attend the meeting?
- A: about 8 people.
- Q: ICAS is protecting the cloud platform? Have you ran ICAS with other MapReduce program at the same time?
- Q: Why tranditional way and 1 node is different?
前言
- hbase 已經到0.19.3了,可惜的是 hbase 0.18.1的api及文件都已經從官方網頁被拿掉了,所幸hbase 0.18 與hbase 0.19相差無幾
- hbase 0.1.3 到 hbase 0.19.3 中間好像已經包含了十幾代,但是其實類似java 1.4 直接跳躍 到 java 5 一樣,hbase 0.1.3 -> hbase 0.2.x -> hbase 0.18.x -> hbase 0.19.x
- 從 hbase 0.18.x 之後,其版本名稱就直接對應hadoop 的版本名稱,如 hbase 0.18 搭配 hadoop 0.18 , hbase 0.19 搭配hadoop 0.19
- 筆者開發hbase時是 hbase 0.13的時代,現在又重拾舊業,發現已經差很多了。如撈取資料的方式:
- hbase 0.13 : select * from 'table_name'
- hbase 0.19 : scan 'table_name'
資料庫結構
table A
column_family:column_quolify1 column_family:column_quolify2 column_family:column_quolify3 row : time stamp 2 cell_value1 cell_value2 cell_value3 row : time stamp 1 cell_value1 cell_value2 cell_value3
- 因此 table A這個資料表,總共有二度的空間,每一度空間又有二維結構。
- 每個 column_family有許多column_quolify1
- 每個 row 又分許多 timestamp
程式碼
- 設計Hbase 的程式,首先要先規劃要建構怎樣功能的程式碼,在看需要用到什麼類別,類別產生出的物件的function可以靠eclipse產生(alt+/)再來挑選
宣告
- 定義宣告以下參數
String table_name = "waue"; String colomn_family = "family:"; String column_quolify= "qf"; String hbase_row = "w-row"; String value = "yes ! good !";
必要條件 資料表屬性:HBaseConfiguration
- 首先,建立HTableDescriptor 物件,用來設定資料表屬性,為必要條件。
HBaseConfiguration config = new HBaseConfiguration();
資料表的特權操作:HBaseAdmin
- HBaseAdmin 用來執行資料庫的建立刪除操作,下面這段是用來檢查是否已經存在這個資料表,沒有的話則新增, 新增時需要用到HTableDescriptor這個類別來新增Column_Family這個成員。此非必要條件,因為不見得每次執行程式都要新建一個表單
- 注意: 在此colomn_family 的後面要以:結尾,如" family:"
HBaseAdmin admin = new HBaseAdmin(config); if (!admin.tableExists(table_name)) { System.out.println("HTable : " + table_name + " creating ... please wait"); HTableDescriptor tableDesc = new HTableDescriptor(table_name); // add column family tableDesc.addFamily(new HColumnDescriptor(colomn_family)); admin.createTable(tableDesc); }
新增/刪除 資料表內容:BatchUpdate
- 接著,我們用BatchUpdate來加入表單內容,我們首先用建構值填入hbase_row,接著用put放入值,用delete刪除值。
- 此非必要條件(也就是沒有用到這個類別程式也能跑),但若是希望能新增或刪除資料的話還是得用到它
注意:這個類別不需要其他類別支援。
BatchUpdate batchUpdate = new BatchUpdate(hbase_row); batchUpdate.put(colomn_family+column_quolify, Bytes.toBytes(value)); batchUpdate.delete(colomn_family+"cellIWantDeleted");
資料表內容:HTable
- HTable 類別在此是用來把之前的建構的內容寫入 ,之後還會用這個類別取得資料表內容,因此也算是必要條件
- HTable 類別用來連接HBaseConfiguration與BatchUpdate,如此完成表單建立 這個類別填入HBaseConfiguration與table_name的建構值,並用commit這個函式輸入之前BatchUpdate建立的表單資料。
HTable table = new HTable(config, table_name); table.commit(batchUpdate);
- 如果你已經知道資料表中的 "row" "colomn_family" "column_quolify" 的資訊,可以用下列方法把該cell的值印出來。
注意: Hbase內的資料屬性雖然是byte,但要用 org.apache.hadoop.hbase.util.Bytes 的 toString(值) 才可以轉出正確格式
Cell cell = table.get(hbase_row, colomn_family+column_quolify); // System.out.print(cell.getValue()); 會印出亂碼,因為資料格式不正確 System.out.print(Bytes.toString(cell.getValue())); // cell value = yes ! good !
掃瞄資料表:Scanner
- 接下來的程式碼用來印出資料表內容,因此需要用到HTable
- Scanner連接到HBase後,怎麼把內容萃取出來呢? 用到 RowResult?承接 Scanner.next()方法,然而一個row裡面,會有 許多colomn_family,每個colomn_family又會有自己的column_quolify,形成colomn_family:column_quolify的二維結構。
- 提供兩個方法 [法一] [法二],方法都一樣,只是步驟有點不同
- getRow() : 把row的名稱秀出來
- get(colomn_family:column_quolify) : 把該cell的值秀出來
- for (RowResult result : scanner) 可以看成是
for (int i=0; i< scanner.length; i++){ RowResult result[i] = scanner[i];
- 但是 scanner沒有 hasnext 或 length的方法,因此用for還滿簡潔的
Scanner scanner = table.getScanner(new String[] { colomn_family+column_quolify }); // 法一 RowResult rowResult = scanner.next(); while (rowResult != null) { System.out.println("Found row: " + Bytes.toString(rowResult.getRow()) + " with value: " + rowResult.get(Bytes .toBytes(colomn_family+column_quolify))); rowResult = scanner.next(); }// 法一完 //法二 for (RowResult result : scanner) { System.out.println("Found row: " + Bytes.toString(result.getRow()) + " with value: " + result.get(Bytes .toBytes(colomn_family+column_quolify))); }// 法二完 scanner.close();
完整程式碼如下
- 完整程式碼如下
import java.io.IOException;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.client.HBaseAdmin;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Scanner;
import org.apache.hadoop.hbase.io.BatchUpdate;
import org.apache.hadoop.hbase.io.Cell;
import org.apache.hadoop.hbase.io.RowResult;
import org.apache.hadoop.hbase.util.Bytes;
public class hbase {
public static void main(String args[]) throws IOException {
String table_name = "waue";
String colomn_family = "family:";
String column_quolify= "qf";
String hbase_row = "w-row";
String value = "0911311311";
HBaseConfiguration config = new HBaseConfiguration();
HBaseAdmin admin = new HBaseAdmin(config);
if (!admin.tableExists(table_name)) {
System.out.println("HTable : " + table_name
+ " creating ... please wait");
HTableDescriptor tableDesc = new HTableDescriptor(table_name);
// add column family
tableDesc.addFamily(new HColumnDescriptor(colomn_family));
admin.createTable(tableDesc);
}
HTable table = new HTable(config, table_name);
BatchUpdate batchUpdate = new BatchUpdate(hbase_row);
batchUpdate.put(colomn_family+column_quolify, Bytes
.toBytes(value));
batchUpdate.delete(colomn_family+"cellIWantDeleted");
table.commit(batchUpdate);
Cell cell = table.get(hbase_row, colomn_family+column_quolify);
System.out.print(cell.getValue());
Scanner scanner =
table.getScanner(new String[] { colomn_family+column_quolify });
RowResult rowResult = scanner.next();
while (rowResult != null) {
System.out.println("Found row: "
+ Bytes.toString(rowResult.getRow())
+ " with value: "
+ rowResult.get(Bytes
.toBytes(colomn_family+column_quolify)));
rowResult = scanner.next();
}
for (RowResult result : scanner) {
System.out.println("Found row: "
+ Bytes.toString(result.getRow())
+ " with value: "
+ result.get(Bytes
.toBytes(colomn_family+column_quolify)));
}
scanner.close();
}
}
ICAS 改寫進度
- no error, no warnning
- 但hbase 內也沒有結果
- reduce error : 要將for迴圈改小於19,否則會出現 arrayIndexOutOfBoundsException
- hbase 的table內沒有東西 : 感覺上是hbase 的語法有錯
- (解法一) 預計重寫整個程式,並精簡化,之後再加上完整功能
- (解法二) 資料庫的部份也許可換成Hive
- (pros) cloudera有hive的支援
- (pros) hive 有可用資料庫語法撈資料,而檔案是個純文字檔,方便於轉成圖檔
- (cons) 要找到相關hadoop&hive的範例程式碼
- (cons) 重新設計資料庫結構
- (cons) 程式碼修改多
nutch on hadoop.nchc.org.tw
- 試看看如何在hadoop.cloudura.0.18.3 上安裝nutch
步驟
我的vm為ubuntu 8.04, 故Disto=hardy
$ sudo su - # cat "deb http://archive.cloudera.com/debian hardy contrib" > /etc/apt/sources.list.d/clouddera.list # cat "deb-src http://archive.cloudera.com/debian hardy contrib" >> /etc/apt/sources.list.d/clouddera.list # curl -s http://archive.cloudera.com/debian/archive.key | apt-key add - # apt-cache search hadoop # exit $ sudo apt-get -y install hadoop hadoop-conf-pseudo hadoop-namenode hadoop-secondarynamenode hadoop-datanode hadoop-jobtracker hadoop-tasktracker
- 安裝目錄
Hadoop wrapper script /usr/bin/hadoop Hadoop config script /etc/default/hadoop Hadoop Configuration Files /etc/hadoop/conf Hadoop Jar and Library Files /usr/lib/hadoop Hadoop Log Files /var/log/hadoop Hadoop Man pages /usr/share/man Hadoop service scripts /etc/init.d/hadoop-*
hbase 0.18.1 port hadoop-cloudera 0.18.3
1. 下載並解壓縮package檔
- patch檔內容如下
#!/bin/bash hbase_ori_home=~/hbase hbase_lib=$hbase_ori_home/lib hadoop_lib=/usr/lib/hadoop/lib hbase_sh=$hbase_ori_home/bin hadoop_sh=/usr/lib/hadoop/bin hbase_conf=$hbase_ori_home/conf hadoop_conf=/etc/hadoop/conf # Install lib cd $hbase_lib sudo cp commons-collections-3.2.jar commons-math-1.1.jar \ jruby-complete-1.1.2.jar lucene-core-2.2.0.jar $hadoop_lib sudo cp ../hbase-*.jar $hadoop_lib # Install hbase_bin cd $hbase_sh sudo cp Formatter.rb hbase-daemons.sh hirb.rb \ start-hbase.sh hbase-daemon.sh HBase.rb regionservers.sh \ stop-hbase.sh hbase $hadoop_sh sudo cp hbase /usr/bin # Install conf cd $hbase_conf sudo cp hbase-default.xml hbase-env.sh hbase-site.xml \ log4j.properties regionservers $hadoop_conf # Install /etc/default/hbase sudo cp $hbase_sh/hbase-config.sh /etc/default/hbase # Install init cd $hbase_ori_home sudo cp hbase-init /etc/init.d/hbase
2. 解壓縮後執行
$ bash ./patch
3. 修改設定 /etc/hadoop/conf/hbase-site.xml
4. 啟動服務
sudo /etc/init.d/hbase-master start sudo /etc/init.d/hbase-regionserver start
5. 開始
$ hbase shell >
pid=$(ps axw -eo pid,command | grep "org.apache.catalina.startup.Bootstrap" | grep "start" | awk '{print $1}')
if [ -z "$pid" ]; then
echo "tomcat is not running"
else
echo "tomcat is detected and the pid is $pid"
kill -9 $pid
if [ -z $? ];then
echo " tomcat ($pid) is killed ..."
else
echo "kill error ..."
fi
fi
shell 裡 for ... in 與 運算 的應用
- example 1 : 批次殺程序
#!/bin/bash
# 把全部apache且start的pid放到變數$str內,若apache的pid 為1011 1012 1013,則$str=1011 1012 1013
str=$(ps axw -eo pid,command |\
grep "apache" | grep "start" |\
awk '{print $1}')
# 雖然kill 支援一次刪除多個檔,如kill -9 1011 1012 1013,但若想要砍一個就喊一下的話,就要用到for...in的應用
count=1
for i in $str
do
echo "string[$count]= $i"
echo "kill -9 $i"
# 注意shell裡的運算要用$((n+n)),而$(...)的用法與`...`相同
count=$(($count+1))
done
- example 2 : 批次改檔名
cd ~
for i in *.[tT][iI][fF]; do
#若目錄內無 .tif 檔案 $i 會傳回 "*.[tT][iI][fF]"
if [ "$i" != "*.[tT][iI][fF]" ]; then
#取得副檔名
subname="`echo $i | awk -F '.' '{print $NF}'`"
#取得主檔名
filename="`echo $i | sed -e s/\.${subname}$//`"
#將 .tif 轉成 .pdf
#tiff2pdf -o "${filename}.pdf" "$i"
mv ${filename}.tif ${filename}.pdf
#若執行成功則刪除 .tif 檔案
if [ $? -eq 0 ]; then
rm -rf $i
fi
fi
done
shell 裡 變數的關係
系統變數 env env - STR=aaa 程序內的全域變數 export export STR=aaa 程序內的區域變數 直接設定 STR=aaa
參考 認識與學習 BASH
java.io.IOException: File XXX could only be replicated to 0 nodes, instead of 1
- 今天系統一直遇到這個問題:
09/07/09 16:37:45 WARN dfs.DFSClient: DataStreamer Exception: org.apache.hadoop.ipc.RemoteException: java.io.IOException: File /user/waue/input/input/hadoop-site.xml could only be replicated to 0 nodes, instead of 1
看了超多人的解法,沒一個有用。後來才發現自己的問題是:硬碟空間不足了,硬碟的使用率99%,難怪hdfs不給寫資料,ok 不過也許還會有不同情況但卻發生這個錯誤訊息。
這個錯誤訊息意思是,他想要放檔案,但沒半個node可以給存取,因此我們需要檢查:
- 系統或hdfs是否還有空間 (像我就是)
- datanode數是否正常
- 是否在safemode
- 讀寫的權限
- 什麼都檢查過都正常的話,也只好砍掉重練了
- ps: 被這bug困住很久,進度嚴重落後中...
eclipse & hadoop plugin 新發現
- 既上次有熱心hadoop使用者寫信告訴我eclipse europa 可以正常使用hadoop 的eclipse plugin ,但一直都沒空去試,今天特地做了一下實驗
- 熱心使用者告訴我 先用eclipse europa開了專案之後就像解封印一樣,即使之後再用eclipse 3.5來開此專案也能正常無誤的進行
- 但今天測試下來發現,eclipse europa確實可以正常無誤的使用hadoop eclipse plugin,但若之後用eclipse 3.5來開,原本存在的問題還是存在。而且之後若再用回eclipse europa來開這個專案,會變成這個專案不會出現在 project eplorer裡,估計是因為eclipse 3.5可能放了些metadata在這個專案中,使得eclipse europa 一讀到這些資訊就起笑了。
結論
- eclipse 3.2 3.3 ~ 3.5 各個版本似乎只有差一點,但其實差個0.1版就很多,plugin在3.3能work的,不見得3.4就可以。
- hadoop eclipse plugin 適用於 eclipse 3.3 版 下載網址於此
- eclipse 設定 hadoop server時,不但port要指定對,連ip、hostname也是有差,(也就是說有可能 localhost:9000 錯,但 127.0.0.1:9000 對)如何給個正確的值,請用 "netstat -altp" 來看其port對應到的host為何。但看hadoop-site.xml當初是給什麼值才是最準的
- 設定正確的話,我可以在自己的電腦上面用eclipse開發好程式後,直接把程序丟到hadoop.nchc.org.tw來運作(但目前node沒有對外ip,因此data or job跑到node後就會無法溝通而停頓)
nutchez 1.3
- 修改工作目錄的bug (如果所在目錄非可以自己讀寫的目錄的話,則會造成檔案有錯,因此在shell內加入cd ~ 即可)
- 修改使用者無法刪除/tmp/search的bug
- 陽明 生物資訊 http://bio.classcloud.org/
- demo picture http://picasaweb.google.com.tw/home
NCHC.Hadoop 運算功能
- 檢查點
| 可選擇的功能 | 運算結果(sec) | 算出花費時間 | 參數個數配置 | 備註 |
| wordcount | v | v(19) | v | |
| mwc | v | v(10) | v | |
| grep | 改正輸出訊息 | x | X | grep (and){ "and,and1,depand"} 有 3個 ,但 wordcount中的 and 只有 1個 |
| nchcgrep | v | v(32) | v | 輸出結果的size會比原本的檔多30倍以上(視一行有多少個字而定) |
| hello | v | v(19) | v | 把字數累加進結果檔 |
| sort | x | 來源檔資料不知為何 |
- wordcount 與 mwc (multi-file wordcount)幾乎沒有差別,最明顯的不同是: mwc 用了 MultiFileInputFormat? 這個類別來設定輸入型態,因此目前測試出,只有在以下情況有些微不同...
- 結果檔內,mwc可以分析的出某些特殊字元,但wordcount卻看成同一個
- mwc運算速度比較快
Eclipse 熱鍵一覽表 (必備)
- 常用熱鍵:
- 可看Navigate -> ...給的建議
看Java Doc Shift + F2 提示可選的類別或成員 Alt + / 程式碼自動排版 Ctrl+Shift+F 將選取的文字註解起來 Ctrl+/ 自動匯入所需要的類別 Ctrl+Shift+O java only 查看使用類別的原始碼 Ctrl+滑鼠左鍵點擊 或 F3 java only 查看類別的階層關係與其成員 F4 查詢有什麼類別可用 Ctrl + Shift + T
- 補充熱鍵:
視景切換 Ctrl+F8 快速執行程式 Ctrl + F11 for java 最大化程序編輯窗口 ctrl + m 快迅定位類中的方法 ctrl + o 顯示打開的文件列表 ctrl+E 全域搜索打開的文件 ctrl+shift+R 打開java的所有class ctrl+shift+T 將選中的小寫轉換為大寫 CTRL+SHIFT+X 將選中的大寫轉換為小寫 CTRL+SHIFT+Y
hadoop programming 完全公式
輸入 key 輸入 value 輸出 Key 輸出 Value Mapper < A , B , C , D > map ( A , B , OutputCollector < C , D > , Reporter reporter ) output . collect ( c , d ) Reducer < C , D , E , F > reduce ( C , Iterator<D> , OutputCollector < E , F > , Reporter reporter ) output . collect ( e , f )
- A, B, C, D ,E, F 分別代表可以用的類別;c, d, e, f 代表由C,D,E,F所產生的物件
- 有了這張表,我們規劃要寫M/R程式的時候:
- 先把Map的輸入<key,value> 應該屬於哪種類別的,則A,B定好
- Map的輸出<key,value>定好,則 C,D也ok了
- 接下來想最終輸出的<key,value>該為何類別,則 E,F 決定好
- 分別填入 ABCDEF之後,整個程式的架構就出來了,接下來就看你的程式如何實做
- 舉例<WordCount> :
- 由於輸入為hdfs的路徑,因此傳到mapper裡時,key= 檔案內每一行的位址、value代表檔案內的每一行字串,因此A可以任意類別,B則為Text
- 而wordcount最終要算出的是每個字的出現次數,因此輸出的<key,value>應該是文字,數字,故 E=Text, F=IntWritable
- 如何才能原本一開始每一行字,進而分析成<文字,數字>,故邏輯為先把每一行的單字都取出,然後設定map的輸出為<單字,1>,以便放到Reduce去相加,所以C=Text, D=IntWritable
- 把ABCDEF填入之後,剩下只是程式邏輯而已!
public static class Map extends MapReduceBase implements Mapper<LongWritable, Text, Text, IntWritable> { private final static IntWritable one = new IntWritable(1); private Text word = new Text(); public void map(LongWritable key, Text value, OutputCollector<Text, IntWritable> output, Reporter reporter) throws IOException { String line = value.toString(); StringTokenizer tokenizer = new StringTokenizer(line); while (tokenizer.hasMoreTokens()) { word.set(tokenizer.nextToken()); output.collect(word, one); } } public static class Reduce extends MapReduceBase implements Reducer<Text, IntWritable, Text, IntWritable> { public void reduce(Text key, Iterator<IntWritable> values, OutputCollector<Text, IntWritable> output, Reporter reporter) throws IOException { int sum = 0; while (values.hasNext()) { sum += values.next().get(); } output.collect(key, new IntWritable(sum)); } }
map 的 key 為 LongWritable? ,然而此key轉型為Text會遇到些run-time-error
原因:Type mismatch in key from map: expected org.apache.hadoop.io.LongWritable?, recieved org.apache.hadoop.io.Text
Map 的 key 從 longWritable 強制轉型到 String,似乎會遇到一些錯
- keyvalue.java
package nchc.keyvalue; import org.apache.hadoop.fs.Path; import org.apache.hadoop.mapred.FileInputFormat; import org.apache.hadoop.mapred.FileOutputFormat; import org.apache.hadoop.mapred.JobClient; import org.apache.hadoop.mapred.JobConf; public class keyvalue{ public static void main(String[] args) { String[] argv = {"input","output","1","1"}; args = argv; if (args.length < 4) { System.out.println("keyvalue <inDir> <outDir> <m> <r>"); return; } JobConf conf = new JobConf(keyvalue.class); conf.setJobName("keyValue"); FileInputFormat.setInputPaths(conf, args[0]); FileOutputFormat.setOutputPath(conf, new Path(args[1])); conf.setNumMapTasks(Integer.parseInt(args[2])); conf.setNumReduceTasks(Integer.parseInt(args[3])); conf.setMapperClass(kvM.class); conf.setReducerClass(kvR.class); long start = System.nanoTime(); try { JobClient.runJob(conf); } catch (Exception e) { e.printStackTrace(); } long period = System.nanoTime() - start; System.err.println(period*(1e-9) + " secs."); } }
- kvm.java (有runtime error)
package nchc.keyvalue;
import java.io.IOException;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapred.MapReduceBase;
import org.apache.hadoop.mapred.Mapper;
import org.apache.hadoop.mapred.OutputCollector;
import org.apache.hadoop.mapred.Reporter;
public class kvM extends MapReduceBase implements
Mapper<LongWritable, Text, Text, Text> {
public void map(LongWritable key, Text value,
OutputCollector<Text, Text> output, Reporter report)
throws IOException {
Text keyv = new Text(key.toString());
output.collect(keyv, value);
}
}
- kvr.java (有runtime error)
package nchc.keyvalue;
import java.io.IOException;
import java.util.Iterator;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapred.MapReduceBase;
import org.apache.hadoop.mapred.OutputCollector;
import org.apache.hadoop.mapred.Reducer;
import org.apache.hadoop.mapred.Reporter;
public class kvR extends MapReduceBase implements
Reducer< Text, Text, Text, Text> {
public void reduce(Text key, Iterator<Text> values,
OutputCollector<Text, Text> output, Reporter report)
throws IOException {
while (values.hasNext()) {
Text keyv = new Text("< "+key+" , ");
Text val = new Text(values.next()+">");
output.collect(keyv, val);
}
}
}
改成以下的map 與 reduce 檔就可以正常運作
- kvM.java
package nchc.keyvalue; import java.io.IOException; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapred.MapReduceBase; import org.apache.hadoop.mapred.Mapper; import org.apache.hadoop.mapred.OutputCollector; import org.apache.hadoop.mapred.Reporter; public class kvM extends MapReduceBase implements Mapper<LongWritable, Text, LongWritable, Text> { public void map(LongWritable key, Text value, OutputCollector<LongWritable, Text> output, Reporter report) throws IOException { output.collect(key, value); } }
- kvR.java
package nchc.keyvalue; import java.io.IOException; import java.util.Iterator; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapred.MapReduceBase; import org.apache.hadoop.mapred.OutputCollector; import org.apache.hadoop.mapred.Reducer; import org.apache.hadoop.mapred.Reporter; public class kvR extends MapReduceBase implements Reducer< LongWritable, Text, Text, Text> { public void reduce(LongWritable key, Iterator<Text> values, OutputCollector<Text, Text> output, Reporter report) throws IOException { while (values.hasNext()) { Text keyv = new Text("< "+key+" , "); Text val = new Text(values.next()+">"); output.collect(keyv, val); } } }
然而就看不到key被reduce起來
- output/part-00000
< 0 , This eBook is for the use of anyone anywhere at no cost and with> < 0 , This eBook is for the use of anyone anywhere at no cost and with> < 66 , almost no restrictions whatsoever. You may copy it, give it away or> < 66 , almost no restrictions whatsoever. You may copy it, give it away or> < 136 , re-use it under the terms of the Project Gutenberg License included> < 136 , re-use it under the terms of the Project Gutenberg License included> < 205 , with this eBook or online at www.gutenberg.net> < 205 , with this eBook or online at www.gutenberg.org> .... (省略)
Java的 類別、抽象、介面
類別
- 類別是實體的,因此他可以繼承(extends),並且可以用new 來產生
- 由以下範例可得知Father whoami = new Son(); 這樣產生出的物件,其實還是Father物件,可想做 (Father)(new Son())父類別的強制轉型
class Father { String Iam = "father"; } class Son extends Father { String Iam = "son"; } public class test { Father whoami = new Son(); System.out.println ( whoami.iam ); }
father
介面
- 介面為需要實做的類別,因此無法用new產生,且無法用extends繼承
- 產生介面唯一能用的是implement在指定的類別上
- implement 可以多重繼承 ,也可以介面implement介面
- 一旦繼承了,就一定要實做內部的功能
- interface的成員可看成是 public static final,因此方法不可以有內容,而變數卻一定要給初值
- 需要被實做的功能,一定有一個特性,就是這個功能會有帶入的參數,於是我們就可以使用這些參數來進行實做
- 以下實做了圖形介面的按鍵,由於implements ActioinListener?,因此要實做actionPerformed功能,而這功能可以用他的event來進行實做
class A extends Applet Implements ActionListener { ... void actionPerformed(ActionEvent event){ event.getSource(); ... } }
抽象類別
- abstract 為抽象類別:當您定義類別時,可以僅宣告方法名稱而不實作當中的邏輯,這樣的方法稱之為「抽象方法」(Abstract method),如果一個類別中包括了抽象方法,則該類別稱之為「抽象類別」(Abstract class),抽象類別是個未定義完全的類別,所以它不能被用來生成物件,它只能被擴充,並於擴充後完成未完成的抽象方法定義。
- extends 繼承來擴充之,一旦將繼承來的abstract方法都實做完成,此類別就可以被繼承
- 因此如果我的類別裡,有用到abstract 的method,就是abstract類別
- 回到第一個範例,Father whoami = new Son(); 感覺很無聊,怎麼不Father whoami = new Son(); 就好了,還要惡搞Father & Son ,難道只是用來出考題的?
- 其實如果Father為抽象類別,Son繼承Father並為實做完後的類別,則Son whoami = new Son();當然ok,但若想要僅用Father的參數,只是透過Son以 new出來(Father為抽象類別無法用new),則Father whoami = new Son(); 就很實用了
釐清 抽象 與 介面
abstract class AC { AC(){ } // abstract would have constructor abstract void method1(); abstract void method2(); } interface INF { // INF(){ } // error : interface cannot have constructor void method1(); void method2(); } public class test { public static void main(String[] args) { // INF if_err1 = new INF; // error : INF cannot be resolved // INF if_err2 = new INF(); // error: Cannot instantiate the type INF INF[] inf = new INF[5]; // declare as array would be work // AC ac_err1 = new AC; // error : AC cannot be resolved // AC ac_err2 = new AC(); // even AC have construstor but still error: Cannot instantiate the type AC AC[] ac = new AC[5]; // declare as array would be work } }
- abstract :Demo可以有自己的數據成員,也可以有非abstarct的成員方法,
- interface:Demo只能夠有靜態的不能被修改的數據成員,所有的成員方法不能有內容。
- 從某種意義上說,interface是一種特殊形式的abstract class。
範例
interface CanFight { void fight(); } interface CanSwim { void swim(); } interface CanFly { void fly(); } interface CanClimb { void climb(); } class ActionCharacter { public void fight() {} } class Hero extends ActionCharacter implements CanFight, CanSwim, CanFly, CanClimb { public void swim() {} public void fly() {} public void climb() {} } public class Ex09 { static void t(CanFight x) { x.fight(); } static void u(CanSwim x) { x.swim(); } static void v(CanFly x) { x.fly(); } static void z(CanClimb x) { x.climb(); } static void w(ActionCharacter x) { x.fight(); } public static void main(String[] args) { Hero h = new Hero(); t(h); // Treat it as a CanFight u(h); // Treat it as a CanSwim v(h); // Treat it as a CanFly z(h); // Treat it as a CanClimb w(h); // Treat it as an ActionCharacter } }
import java.io.File;
import java.io.IOException;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.fs.FileUtil;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.MultiRegionTable;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.io.BatchUpdate;
import org.apache.hadoop.hbase.io.Cell;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.io.RowResult;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.mapred.JobClient;
import org.apache.hadoop.mapred.JobConf;
import org.apache.hadoop.mapred.MapReduceBase;
import org.apache.hadoop.mapred.MiniMRCluster;
import org.apache.hadoop.mapred.OutputCollector;
import org.apache.hadoop.mapred.Reporter;
/**
* Test Map/Reduce job over HBase tables. The map/reduce process we're testing
* on our tables is simple - take every row in the table, reverse the value of
* a particular cell, and write it back to the table.
*/
public class TestTableMapReduce extends MultiRegionTable {
private static final Log LOG =
LogFactory.getLog(TestTableMapReduce.class.getName());
static final String MULTI_REGION_TABLE_NAME = "mrtest";
static final String INPUT_COLUMN = "contents:";
static final String OUTPUT_COLUMN = "text:";
private static final byte [][] columns = new byte [][] {
Bytes.toBytes(INPUT_COLUMN),
Bytes.toBytes(OUTPUT_COLUMN)
};
/** constructor */
public TestTableMapReduce() {
super(INPUT_COLUMN);
desc = new HTableDescriptor(MULTI_REGION_TABLE_NAME);
desc.addFamily(new HColumnDescriptor(INPUT_COLUMN));
desc.addFamily(new HColumnDescriptor(OUTPUT_COLUMN));
}
/**
* Pass the given key and processed record reduce
*/
public static class ProcessContentsMapper
extends MapReduceBase
implements TableMap<ImmutableBytesWritable, BatchUpdate> {
/**
* Pass the key, and reversed value to reduce
* @param key
* @param value
* @param output
* @param reporter
* @throws IOException
*/
public void map(ImmutableBytesWritable key, RowResult value,
OutputCollector<ImmutableBytesWritable, BatchUpdate> output,
Reporter reporter)
throws IOException {
if (value.size() != 1) {
throw new IOException("There should only be one input column");
}
byte [][] keys = value.keySet().toArray(new byte[value.size()][]);
if(!Bytes.equals(keys[0], Bytes.toBytes(INPUT_COLUMN))) {
throw new IOException("Wrong input column. Expected: '" + INPUT_COLUMN
+ "' but got: '" + Bytes.toString(keys[0]) + "'");
}
// Get the original value and reverse it
String originalValue =
new String(value.get(keys[0]).getValue(), HConstants.UTF8_ENCODING);
StringBuilder newValue = new StringBuilder();
for(int i = originalValue.length() - 1; i >= 0; i--) {
newValue.append(originalValue.charAt(i));
}
// Now set the value to be collected
BatchUpdate outval = new BatchUpdate(key.get());
outval.put(OUTPUT_COLUMN, Bytes.toBytes(newValue.toString()));
output.collect(key, outval);
}
}
/**
* Test a map/reduce against a multi-region table
* @throws IOException
*/
public void testMultiRegionTable() throws IOException {
runTestOnTable(new HTable(conf, MULTI_REGION_TABLE_NAME));
}
private void runTestOnTable(HTable table) throws IOException {
MiniMRCluster mrCluster = new MiniMRCluster(2, fs.getUri().toString(), 1);
JobConf jobConf = null;
try {
LOG.info("Before map/reduce startup");
jobConf = new JobConf(conf, TestTableMapReduce.class);
jobConf.setJobName("process column contents");
jobConf.setNumReduceTasks(1);
TableMapReduceUtil.initTableMapJob(Bytes.toString(table.getTableName()),
INPUT_COLUMN, ProcessContentsMapper.class,
ImmutableBytesWritable.class, BatchUpdate.class, jobConf);
TableMapReduceUtil.initTableReduceJob(Bytes.toString(table.getTableName()),
IdentityTableReduce.class, jobConf);
LOG.info("Started " + Bytes.toString(table.getTableName()));
JobClient.runJob(jobConf);
LOG.info("After map/reduce completion");
// verify map-reduce results
verify(Bytes.toString(table.getTableName()));
} finally {
mrCluster.shutdown();
if (jobConf != null) {
FileUtil.fullyDelete(new File(jobConf.get("hadoop.tmp.dir")));
}
}
}
private void verify(String tableName) throws IOException {
HTable table = new HTable(conf, tableName);
boolean verified = false;
long pause = conf.getLong("hbase.client.pause", 5 * 1000);
int numRetries = conf.getInt("hbase.client.retries.number", 5);
for (int i = 0; i < numRetries; i++) {
try {
LOG.info("Verification attempt #" + i);
verifyAttempt(table);
verified = true;
break;
} catch (NullPointerException e) {
// If here, a cell was empty. Presume its because updates came in
// after the scanner had been opened. Wait a while and retry.
LOG.debug("Verification attempt failed: " + e.getMessage());
}
try {
Thread.sleep(pause);
} catch (InterruptedException e) {
// continue
}
}
assertTrue(verified);
}
/**
* Looks at every value of the mapreduce output and verifies that indeed
* the values have been reversed.
* @param table Table to scan.
* @throws IOException
* @throws NullPointerException if we failed to find a cell value
*/
private void verifyAttempt(final HTable table) throws IOException, NullPointerException {
Scan scan = new Scan();
scan.addColumns(columns);
ResultScanner scanner = table.getScanner(scan);
try {
for (Result r : scanner) {
if (LOG.isDebugEnabled()) {
if (r.size() > 2 ) {
throw new IOException("Too many results, expected 2 got " +
r.size());
}
}
byte[] firstValue = null;
byte[] secondValue = null;
int count = 0;
for(Map.Entry<byte [], Cell> e: r.getRowResult().entrySet()) {
if (count == 0) {
firstValue = e.getValue().getValue();
}
if (count == 1) {
secondValue = e.getValue().getValue();
}
count++;
if (count == 2) {
break;
}
}
String first = "";
if (firstValue == null) {
throw new NullPointerException(Bytes.toString(r.getRow()) +
": first value is null");
}
first = new String(firstValue, HConstants.UTF8_ENCODING);
String second = "";
if (secondValue == null) {
throw new NullPointerException(Bytes.toString(r.getRow()) +
": second value is null");
}
byte[] secondReversed = new byte[secondValue.length];
for (int i = 0, j = secondValue.length - 1; j >= 0; j--, i++) {
secondReversed[i] = secondValue[j];
}
second = new String(secondReversed, HConstants.UTF8_ENCODING);
if (first.compareTo(second) != 0) {
if (LOG.isDebugEnabled()) {
LOG.debug("second key is not the reverse of first. row=" +
r.getRow() + ", first value=" + first + ", second value=" +
second);
}
fail();
}
}
} finally {
scanner.close();
}
}
}
* hbase 使用 參考
- 更多code
查看 hbase/src/java/org/apache/hadoop/hbase 內 有何java 檔有 main
find $hbase/src/java/org.apache/hadoop/hbase |xargs grep "main"
- 我的hbase log =
/var/log/hadoop/hbase-hadoop-master-vm1.log
/**
* Copyright 2008 The Apache Software Foundation
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package hbase;
import java.io.IOException;
import java.util.Map;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.io.Cell;
import org.apache.hadoop.hbase.io.HbaseMapWritable;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.io.RowResult;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.mapred.FileOutputFormat;
import org.apache.hadoop.mapred.JobClient;
import org.apache.hadoop.mapred.JobConf;
import org.apache.hadoop.mapred.OutputCollector;
import org.apache.hadoop.mapred.Reporter;
import org.apache.hadoop.mapred.lib.IdentityReducer;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
/**
* A job with a map to count rows.
* Map outputs table rows IF the input row has columns that have content.
* Uses an {@link IdentityReducer}
*/
public class RowCounter extends TableMap<ImmutableBytesWritable, RowResult> implements Tool {
/* Name of this 'program'
*/
static final String NAME = "rowcounter";
private Configuration conf;
private final RowResult EMPTY_RESULT_VALUE =
new RowResult(Bytes.toBytes("dummy"),new HbaseMapWritable<byte [], Cell>());
private static enum Counters {ROWS}
@Override
public void map(ImmutableBytesWritable row, RowResult value,
OutputCollector<ImmutableBytesWritable, RowResult> output,
@SuppressWarnings("unused") Reporter reporter)
throws IOException {
boolean content = false;
for (Map.Entry<byte [], Cell> e: value.entrySet()) {
Cell cell = e.getValue();
if (cell != null && cell.getValue().length > 0) {
content = true;
break;
}
}
if (!content) {
return;
}
// Give out same value every time. We're only interested in the row/key
reporter.incrCounter(Counters.ROWS, 1);
output.collect(row, EMPTY_RESULT_VALUE);
}
/**
* @param args
* @return the JobConf
* @throws IOException
*/
@SuppressWarnings({ "unused", "deprecation" })
public JobConf createSubmittableJob(String[] args) throws IOException {
JobConf c = new JobConf(getConf(), RowCounter.class);
c.setJobName(NAME);
// Columns are space delimited
StringBuilder sb = new StringBuilder();
final int columnoffset = 2;
for (int i = columnoffset; i < args.length; i++) {
if (i > columnoffset) {
sb.append(" ");
}
sb.append(args[i]);
}
// Second argument is the table name.
TableMap.initJob(args[1], sb.toString(), this.getClass(),
ImmutableBytesWritable.class, RowResult.class, c);
c.setReducerClass(IdentityReducer.class);
// First arg is the output directory.
FileOutputFormat.setOutputPath(c, new Path(args[0]));
return c;
}
static int printUsage() {
System.out.println(NAME +
" <outputdir> <tablename> <column1> [<column2>...]");
return -1;
}
public int run(final String[] args) throws Exception {
// Make sure there are at least 3 parameters
if (args.length < 3) {
System.err.println("ERROR: Wrong number of parameters: " + args.length);
return printUsage();
}
JobClient.runJob(createSubmittableJob(args));
return 0;
}
public Configuration getConf() {
return this.conf;
}
public void setConf(final Configuration c) {
this.conf = c;
}
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
String[] argv = {"/user/waue/hba","t1","f2:c1"};
args = argv;
HBaseConfiguration c = new HBaseConfiguration();
int errCode = ToolRunner.run(c, new RowCounter(), args);
System.exit(errCode);
}
}
- 要run此code,第一個參數是輸出路徑,第二個參數是資料表的名稱,第三個參數是column
- 其中: String[] argv = {"/user/waue/hba","t1","f2:c1"};
- 要先建立t1資料表,以及f2:c1的資料 column 才能跑
icas 0.1版完成
/** * Program SnortProduce.java * Editor: Waue Chen * From : GTD. NCHC. Taiwn * Last Update Date: 07/29/2009 * support version : hadoop 0.18.3, hbase 0.18.1 */ package tw.org.nchc.code; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.Iterator; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configured; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.HColumnDescriptor; import org.apache.hadoop.hbase.HTableDescriptor; import org.apache.hadoop.hbase.client.HBaseAdmin; import org.apache.hadoop.hbase.client.HTable; import org.apache.hadoop.hbase.io.BatchUpdate; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.hadoop.hbase.mapred.TableReduce; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapred.FileInputFormat; import org.apache.hadoop.mapred.FileOutputFormat; import org.apache.hadoop.mapred.JobClient; import org.apache.hadoop.mapred.JobConf; import org.apache.hadoop.mapred.MapReduceBase; import org.apache.hadoop.mapred.Mapper; import org.apache.hadoop.mapred.OutputCollector; import org.apache.hadoop.mapred.Reducer; import org.apache.hadoop.mapred.Reporter; import org.apache.hadoop.util.Tool; import org.apache.hadoop.util.ToolRunner; public class ICAS extends Configured implements Tool { HBaseConfiguration hbase_conf; HBaseAdmin hbase_admin; public ICAS() throws IOException { hbase_conf = new HBaseConfiguration(); hbase_admin = new HBaseAdmin(hbase_conf); } public static class ICAS_M extends MapReduceBase implements Mapper<LongWritable, Text, Text, Text> { String getip(String str) { String[] ret = str.split(":"); return ret[0]; } public void map(LongWritable key, Text value, OutputCollector<Text, Text> output, Reporter reporter) throws IOException { // [3] sig [4]class [5]y [6]m [7]d [8]h [9]M [10]s [11]s [12]d [13]t String line = value.toString(); String[] str = line.split(";"); String source_ip = getip(str[11]); String dest_ip = getip(str[12]); String fkey = dest_ip ; String date = str[5] + "/" + str[6] + "/" + str[7] + "_" + str[8] + ":" + str[9] + ":" + str[10]; // source @ date @ sig @ class @ type String fvalue = source_ip + "@" + date + "@" + str[3] +"@" +str[4] + "@"+ str[13]; output.collect(new Text(fkey), new Text(fvalue)); } } public static class ICAS_R extends TableReduce<Text, Text> { public void reduce(Text key, Iterator<Text> values, OutputCollector<ImmutableBytesWritable, BatchUpdate> output, Reporter reporter) throws IOException { HTable table = new HTable("ICAS"); String source_ip; String date; String sig_class; String type; String signature; String rawstr = new String(values.next().getBytes()); String[] str = rawstr.split("@"); source_ip = str[0]; date = str[1]; signature = str[2]; sig_class = str[3]; type = str[4]; // values.next().getByte() can get value and transfer to byte form, while (values.hasNext()) { // source_ip + "@" + date + "@" + sig + "@" + class + "@" + type; rawstr = new String(values.next().getBytes()); str = rawstr.split("@"); source_ip = source_ip + " ; " + str[0]; date = date + " ; " + str[1]; signature = signature + ";" + str[2]; } reporter.setStatus("amp emitting cell for row'" + key.toString() + "'"); BatchUpdate map = new BatchUpdate(key.toString()); // map.setTimestamp(timestamp); map.put("infor:source_ip", Bytes.toBytes(source_ip)); map.put("infor:signature", Bytes.toBytes(signature)); map.put("infor:date", Bytes.toBytes(date)); map.put("infor:class", Bytes.toBytes(sig_class)); map.put("infor:type", Bytes.toBytes(type)); table.commit(map); // ImmutableBytesWritable Hkey = new ImmutableBytesWritable(Bytes // .toBytes(key.toString())); // output.collect(Hkey, map); } } public static class ICAS_T extends MapReduceBase implements Reducer<Text, Text, Text, Text> { public void reduce(Text key, Iterator<Text> values, OutputCollector<Text, Text> output, Reporter reporter) throws IOException { StringBuilder ret = new StringBuilder("\n"); while (values.hasNext()) { String v = values.next().toString().trim(); if (v.length() > 0) ret.append(v + "\n"); } output.collect((Text) key, new Text(ret.toString())); } } /** * A reducer class that just emits the sum of the input values. */ public boolean checkTableExist(String table_name) throws IOException { if (!hbase_admin.tableExists(table_name)) { return false; } return true; } // create Hbase table , success = 1 ; failse = 0; Table_exist = 2; public boolean createTable(String table_name, String[] column_family) throws IOException { // check whether Table name exite or not if (!checkTableExist(table_name)) { HTableDescriptor tableDesc = new HTableDescriptor(table_name); for (int i = 0; i < column_family.length; i++) { String cf = column_family[i]; // check and correct name format "string:" if (!cf.endsWith(":")) { column_family[i] = cf + ":"; } // add column family tableDesc.addFamily(new HColumnDescriptor(column_family[i])); } hbase_admin.createTable(tableDesc); return true; } else { return false; } } static boolean hdfsput(String source_file, String text_tmp) { try { Process p = Runtime.getRuntime().exec( "hadoop dfs -put " + source_file + " " + text_tmp); BufferedReader in = new BufferedReader(new InputStreamReader(p .getErrorStream())); String err = null; while ((err = in.readLine()) != null) { System.err.println(err); } System.err.println("finish"); return true; } catch (Exception e) { e.printStackTrace(); return false; } } int printUsage() { System.out .println("ICAS <sourceFile> <tempFile> <tableName> <mapNumber> <reduceNumber> "); ToolRunner.printGenericCommandUsage(System.out); return -1; } public int run(String[] args) throws Exception { Path text_path = new Path(args[1]); // text path Path output = new Path("/tmp/output"); // /tmp/output /* set conf */ JobConf conf = new JobConf(getConf(), ICAS.class); conf.setJobName("SnortProduce"); // key point conf.setOutputKeyClass(Text.class); conf.setOutputValueClass(Text.class); /* set mapper and reducer */ conf.setMapperClass(ICAS_M.class); conf.setReducerClass(ICAS_R.class); // conf.setMapperClass(IdentityMapper.class); // conf.setReducerClass(IdentityReducer.class); /* delete previous output dir */ if (FileSystem.get(conf).exists(output)) FileSystem.get(conf).delete(output, true); conf.setNumMapTasks(Integer.parseInt(args[3])); conf.setNumReduceTasks(Integer.parseInt(args[4])); /* set input path */ FileInputFormat.setInputPaths(conf, text_path); FileOutputFormat.setOutputPath(conf, output); /* run */ JobClient.runJob(conf); return 0; } public static void main(String[] args) throws Exception { /* Major parameter */ // it indicates local path, not hadoop file system path String source_file = "/home/waue/log"; // data source tmp String text_tmp = "/user/waue/parsed"; /* Minor parameter */ String table_name = "ICAS"; String[] argv = { source_file, text_tmp, table_name, "1", "1" }; args = argv; /* build table */ String[] col_family = { "infor:" }; BuildHTable build_table = new BuildHTable(); if (!build_table.checkTableExist(args[2])) { if (!build_table.createTable(args[2], col_family)) { System.err.println("create table error !"); } } else { System.err.println("Table \"" + args[2] + "\" has already existed !"); } // if (!hdfsput(args[0], args[1])) { // System.out.println("directory is existed."); // } int res = ToolRunner.run(new Configuration(), new ICAS(), args); System.exit(res); } }
測試資料:
1;2404;5;attack_method_1;Attempted_Privilege;1;08;06;16;09;46;1.2.3.4:3394;140.110.138.22:445;TCP; 1;2404;5;attack_method_1;Attempted_Privilege;1;08;06;16;09;48;5.6.7.8:3394;140.110.138.22:445;TCP; 1;2404;5;attack_method_2;Attempted_Privilege;1;08;06;16;09;48;5.6.7.8:3394;140.110.138.22:445;TCP; 1;2404;5;attack_method_3;Attempted_Privilege;1;08;06;16;09;48;5.6.7.8:3394;140.110.138.22:445;TCP; 1;2404;5;attack_method_4;Attempted_Privilege;1;08;06;16;09;48;5.6.7.8:3394;140.110.138.22:445;TCP; 1;2404;5;attack_method_1;Attempted_Privilege;1;08;06;16;09;48;5.6.7.8:3394;140.110.141.33:445;TCP;
結果:
hbase(main):005:0> scan 'ICAS'
ROW COLUMN+CELL
140.110.138.22 column=infor:class, timestamp=1248863177234, value=Attempted_Privilege
140.110.138.22 column=infor:date, timestamp=1248863177234, value=1/08/06_16:09:46 ; 1/08/06_16:0
9:48 ; 1/08/06_16:09:48 ; 1/08/06_16:09:48 ; 1/08/06_16:09:48
140.110.138.22 column=infor:signature, timestamp=1248863177234, value=attack_method_1;attack_met
hod_1;attack_method_2;attack_method_3;attack_method_4
140.110.138.22 column=infor:source_ip, timestamp=1248863177234, value=1.2.3.4 ; 5.6.7.8 ; 5.6.7.
8 ; 5.6.7.8 ; 5.6.7.8
140.110.138.22 column=infor:type, timestamp=1248863177234, value=TCP
140.110.141.33 column=infor:class, timestamp=1248863177268, value=Attempted_Privilege
140.110.141.33 column=infor:date, timestamp=1248863177268, value=1/08/06_16:09:48
140.110.141.33 column=infor:signature, timestamp=1248863177268, value=attack_method_1
140.110.141.33 column=infor:source_ip, timestamp=1248863177268, value=5.6.7.8
140.110.141.33 column=infor:type, timestamp=1248863177268, value=TCP
10 row(s) in 0.1550 seconds
- 問題1: 如何讓run裡宣告的物件,map可使用,reduce也可以呼叫到
public class ICAS extends Configured implements Tool { HBaseConfiguration hbase_conf; HBaseAdmin hbase_admin; public ICAS() throws IOException { hbase_conf = new HBaseConfiguration(); hbase_admin = new HBaseAdmin(hbase_conf); } public static class ICAS_M extends MapReduceBase implements Mapper<LongWritable, Text, Text, Text> { //無法用hbase_admin, hbase_conf } public static class ICAS_R extends TableReduce<Text, Text> { //無法用hbase_admin, hbase_conf } public static void main(String[] args) throws Exception { //可以用hbase_admin, hbase_conf }
- 問題二、如何不覆蓋原本hbase內的資料,而是累加進去
- 要先從原本的資料庫把資料撈出來,再整合後放進去
- 問題三、如何讓reduce 顯示進度
- 問題四、如何讓<key,value>後的value 在進行一次<key,value>
- 現在:
key= dest ip value= infor: sip host M host1; host2; host1
- 期望值:(也就是多出來的host1要被濾掉)
key= dest ip value= infor: sip host M host1; host2
test
雲端運算基礎課程
- nutch 投影片 , 實做 , 其他實做調整, pipes and streaming
2009 - 03 - 30 : 上午
課目 時間 長度 0. 課程介紹與自我介紹時間 10 min 9:30~9:40 1. 雲端運算簡介 1h 9:40~10:30 2. Hadoop簡介 50 min 10:40~11:30 實作一: Hadoop 單機安裝 20 min 11:30~11:50
2009 - 03 - 30 : 下午
課目 時間 長度 3. HDFS 介紹 1h 13:00~14:00 實作二: HDFS 指令操作練習 1h 14:00~15:00 4. 叢集環境設定說明 50 min 15:10~16:00 實做三: Hadoop 叢集安裝與 HDFS 指令操作練習 1h 16:00~17:00
2009 - 03 - 31 : 上午
課目 時間 長度 5. MapReduce簡介 40 min 9:35~10:10 6. Hadoop MapReduce 程式設計解說 50 min 10:15~11:10 實作四: MapReduce 範例實做 20 min 11:20 ~ 11:40 7. 小結 10 min
2009 - 03 - 31 : 下午
課目 時間 長度 8. drbl 課程 40min 實作: 運用 DRBL 將電腦教室轉化為 Hadoop 叢集 3h
學員課程上建議:
- 多舉例應用範圍
- 多解釋web ui
- 找出更多範例
- 感受錯誤容忍機制、體驗大量處理機制
- 增加hadoop-default.xml的有用參數
問卷之改進反應
1. 進階程式設計,例如一些新技術或是新應用 2. 希望在南部也能開一場 3. 雲端計算課程進階(load balance,容錯示範..etc),雲端計算課程程式實做(nutch),雲端計算結合DRBL實做(如何快速部屬雲端叢集),雲端計算+HBase 5. 雲端計算實做步驟可再詳盡一些,希望回去自己實做時照網頁步驟也可以完成,不侷限在國網電腦教室環境. 如果可以再加上操作影片示範會更好 6. 實際應用部分可以在多一些實作
問題
- server如何增加client 數
- 是否能連到正確的namenode取決於conf/hadoop-site.xml
$ bin/hadoop-daemon.sh --config ./conf start datanode starting datanode, logging to /tmp/hadoop/logs/hadoop-waue-datanode-Dx7200.out $ bin/hadoop-daemon.sh --config ./conf start tasktracker starting tasktracker, logging to /tmp/hadoop/logs/hadoop-waue-tasktracker-Dx7200.out
- 是否能連到正確的namenode取決於conf/hadoop-site.xml
- 檔案大小限制
- 如何看區塊放在哪個節點上
- 點到該檔案頁面後,出現在最下方
| -5300341523868264468: | 140.110.141.129:50010 | 140.110.138.191:50010 |
- 如何升級降級hadoop
前言
- 做完之前的實做,已經對hadoop有一定的體驗,然而各位也許心中有些疑問,就是我學了hadoop到底可以用來..?,因此在此介紹一個hadoop的應用,搜尋引擎nutch
- 此篇的重點在於
- 完整的安裝nutch
- 用hadoop的角度來架設nutch
- 解決中文亂碼問題
- 搜尋引擎不只是找網頁內的資料,也能爬到網頁內的檔案(如pdf,msword)
- 也可運行在多台node
環境
- 目錄
| /opt/nutch | nutch 家目錄 |
| /opt/nutch/conf | nutch設定檔 |
| /opt/hadoop | hadoop家目錄 |
| /opt/hadoop/conf | hadoop設定檔 |
step 1 安裝好Hadoop
單機版
可以用實做一的方法來安裝單機
- 執行
~$ cd /opt /opt$ sudo wget http://ftp.twaren.net/Unix/Web/apache/hadoop/core/hadoop-0.18.3/hadoop-0.18.3.tar.gz /opt$ sudo tar zxvf hadoop-0.18.3.tar.gz /opt$ sudo mv hadoop-0.18.3/ hadoop /opt$ sudo chown -R hadooper:hadooper hadoop /opt$ cd hadoop/ /opt/hadoop$ gedit conf/hadoop-env.sh
在任一行內貼上
export JAVA_HOME=/usr/lib/jvm/java-6-sun export HADOOP_HOME=/opt/hadoop export HADOOP_CONF_DIR=/opt/hadoop/conf export HADOOP_LOG_DIR=/tmp/hadoop/logs export HADOOP_PID_DIR=/tmp/hadoop/pid
- 執行
/opt/hadoop$ gedit conf/hadoop-site.xml
用以下內容取代整個檔案
<configuration>
<property>
<name>fs.default.name</name>
<value>hdfs://localhost:9000/</value>
<description> </description>
</property>
<property>
<name>mapred.job.tracker</name>
<value>localhost:9001</value>
<description> </description>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/tmp/hadoop/hadoop-${user.name}</value>
<description> </description>
</property>
</configuration>
- 接著執行
/opt/hadoop$ bin/hadoop namenode -format /opt/hadoop$ bin/start-all.sh
- 啟動之後,可以檢查以下網址,來觀看服務是否正常。 Hadoop 管理介面 Hadoop Task Tracker 狀態 Hadoop DFS 狀態
叢集版
請參考實作三
step 2 nutch下載與安裝
2.0 設定環境
- 系統環境變數內加入java_home的路徑
$ sudo su - # echo "export JAVA_HOME=/usr/lib/jvm/java-6-sun" >> /etc/bash.bashrc # chown -R hadooper /opt # exit # exit
- 停止原本的hadoop
$ cd /opt/hadoop $ bin/stop-all.sh
2.1 下載 nutch 並解壓縮
- nutch 1.0 (2009/03/28 release )
$ cd /opt $ wget http://ftp.twaren.net/Unix/Web/apache/lucene/nutch/nutch-1.0.tar.gz $ tar -zxvf nutch-1.0.tar.gz $ mv nutch-1.0 nutch
2.2 部屬hadoop,nutch目錄結構
$ cp -rf /opt/hadoop/* /opt/nutch
2.3 複製函式庫檔
$ cd nutch $ cp -rf *.jar lib/
step 3 編輯設定檔
- 所有的設定檔都在 /opt/nutch/conf 下
3.1 $NUTCH_HOME/conf/hadoop-env.sh
$ cd /opt/nutch/conf $ gedit hadoop-env.sh
* 將找到原本再hadoop-env.sh的設定,將之改成以下設定
export JAVA_HOME=/usr/lib/jvm/java-6-sun export HADOOP_HOME=/opt/nutch export HADOOP_CONF_DIR=/opt/nutch/conf export HADOOP_SLAVES=$HADOOP_CONF_DIR/slaves export HADOOP_LOG_DIR=/tmp/hadoop/logs export HADOOP_PID_DIR=/tmp/hadoop/pid export NUTCH_HOME=/opt/nutch export NUTCH_CONF_DIR=/opt/nutch/conf
- 載入環境設定值
$ source ./hadoop-env.sh
- ps:強烈建議寫入 /etc/bash.bashrc 中比較萬無一失!!
3.2 $NUTCH_HOME/conf/nutch-site.xml
- 重要的設定檔,新增了必要的內容於內,然而想要瞭解更多參數資訊,請見nutch-default.xml
$ gedit nutch-site.xml
<configuration> <property> <name>http.agent.name</name> <value>nutch</value> <description>HTTP 'User-Agent' request header. </description> </property> <property> <name>http.agent.description</name> <value>MyTest</value> <description>Further description</description> </property> <property> <name>http.agent.url</name> <value>localhost</value> <description>A URL to advertise in the User-Agent header. </description> </property> <property> <name>http.agent.email</name> <value>test@test.org.tw</value> <description>An email address </description> </property> <property> <name>plugin.folders</name> <value>/opt/nutch/plugins</value> <description>Directories where nutch plugins are located. </description> </property> <property> <name>plugin.includes</name> <value>protocol-(http|httpclient)|urlfilter-regex|parse-(text|html|js|ext|msexcel|mspowerpoint|msword|oo|pdf|rss|swf|zip)|index-(more|basic|anchor)|query-(more|basic|site|url)|response-(json|xml)|summary-basic|scoring-opic|urlnormalizer-(pass|regex|basic)</value> <description> Regular expression naming plugin directory names</description> </property> <property> <name>parse.plugin.file</name> <value>parse-plugins.xml</value> <description>The name of the file that defines the associations between content-types and parsers.</description> </property> <property> <name>db.max.outlinks.per.page</name> <value>-1</value> <description> </description> </property> <property> <name>http.content.limit</name> <value>-1</value> </property> <property> <name>indexer.mergeFactor</name> <value>500</value> <description>The factor that determines the frequency of Lucene segment merges. This must not be less than 2, higher values increase indexing speed but lead to increased RAM usage, and increase the number of open file handles (which may lead to "Too many open files" errors). NOTE: the "segments" here have nothing to do with Nutch segments, they are a low-level data unit used by Lucene. </description> </property> <property> <name>indexer.minMergeDocs</name> <value>500</value> <description>This number determines the minimum number of Lucene Documents buffered in memory between Lucene segment merges. Larger values increase indexing speed and increase RAM usage. </description> </property> </configuration>
3.3 $NUTCH_HOME/conf/crawl-urlfilter.txt
- 重新編輯爬檔規則,此檔重要在於若設定不好,則爬出來的結果幾乎是空的,也就是說最後你的搜尋引擎都找不到資料啦!
$ gedit ./crawl-urlfilter.txt
# skip ftp:, & mailto: urls -^(ftp|mailto): # skip image and other suffixes we can't yet parse -\.(gif|GIF|jpg|JPG|png|PNG|ico|ICO|css|sit|eps|wmf|mpg|xls|gz|rpm|tgz|mov|MOV|exe|jpeg|JPEG|bmp|BMP)$ # skip URLs containing certain characters as probable queries, etc. -[*!@] # accecpt anything else +.*
3.4 環境若要設定成叢集才要做
- 若是單機版則不用處理此節
- 完全複製到node2
$ ssh node02 "sudo chown hadooper:hadooper /opt" $ scp -r /opt/nutch node02:/opt/
step 4 執行nutch
- 先再/opt/nutch內啟動hadoop
$ cd /opt/nutch $ bin/start-all.sh
- 請到 管理頁面看是否正常
4.1 編輯url清單
$ cd /opt/nutch $ mkdir urls $ echo "http://www.nchc.org.tw/tw/" >> ./urls/urls.txt
4.2 上傳清單到HDFS
$ bin/hadoop dfs -put urls urls
4.3 執行nutch crawl
- 用下面的指令就可以命令nutch開始工作了,之後map reduce會瘋狂工作
$ bin/nutch crawl urls -dir search -threads 2 -depth 3 -topN 100000
- 執行上個指令會把執行過程秀在stdout上。若想要以後慢慢看這些訊息,可以用io導向的方式傾倒於日誌檔
$ bin/nutch crawl urls -dir search -threads 2 -depth 3 -topN 100000 >& nutch.log
- 執行上個指令會把執行過程秀在stdout上。若想要以後慢慢看這些訊息,可以用io導向的方式傾倒於日誌檔
- 在nutch運作的同時,可以在node01節點用瀏覽器,透過 job管理頁面, hdfs管理頁面, 程序運作頁面 來監看程序。
ps: 重要!!! 如果錯誤訊息出現
Exception in thread "main" java.lang.RuntimeException: java.lang.ClassNotFoundException: org.apache.hadoop.dfs.DistributedFileSystem
則代表之前沒有做此2.2的"複製函式庫檔"的步驟,請將hadoop-0.18.3*.jar 拷貝到lib中再執行一次即可
step 5 瀏覽搜尋結果
- nutch 在 step 4 的工作是把你寫在urls.txt檔內的網址,用map reduce的程序來進行資料分析,但是分析完之後,要透過tomcat來觀看結果。以下就是安裝與設定你的客製化搜尋引擎的步驟。
5.1 安裝tomcat
- 下載tomcat
$ cd /opt/ $ wget http://ftp.twaren.net/Unix/Web/apache/tomcat/tomcat-6/v6.0.18/bin/apache-tomcat-6.0.18.tar.gz
- 解壓縮
$ tar -xzvf apache-tomcat-6.0.18.tar.gz $ mv apache-tomcat-6.0.18 tomcat
5.1 tomcat server設定
- 修改 /opt/tomcat/conf/server.xml 以修正中文亂碼問題
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8" useBodyEncodingForURI="true" />
5.3 下載crawl結果
- 先把放在hdfs上,nutch的運算結果下載到local端
$ cd /opt/nutch $ bin/hadoop dfs -get search /opt/search
5.4 設定nutch的搜尋引擎頁面到tomcat
- 把nutch的搜尋引擎頁面取代為tomcat的webapps/ROOT
$ cd /opt/nutch $ mkdir web $ cd web $ jar -xvf ../nutch-1.0.war $ mv /opt/tomcat/webapps/ROOT /opt/tomcat/webapps/ROOT-ori $ cd /opt/nutch $ mv /opt/nutch/web /opt/tomcat/webapps/ROOT
5.5 設定搜尋引擎內容的來源路徑
- 5.4的步驟雖然設定好搜尋引擎的頁面,然而其只能當作是介面而已,因此這個步驟把要搜尋的內容與搜尋介面做個連結
$ gedit /opt/tomcat/webapps/ROOT/WEB-INF/classes/nutch-site.xml
<configuration>
<property>
<name>searcher.dir</name>
<value>/opt/search</value>
</property>
</configuration>
5.6 啟動tomcat
$ /opt/tomcat/bin/startup.sh
step 6 享受結果
Enjoy ! http://localhost:8080
- 參考資料:
OpenSSL Programing : Connection
用Eclipse製成可在Hadoop上運行MapReduce的jar檔
ps : 需eclipse 3.3 以上 搭配 hadoop 0.17 以上版本。
- 本篇的安裝環境是
名稱 目錄 Hadoop 安裝目錄 /opt/hadoop 來源資料夾 /opt/hadoop/input 輸出資料夾 /opt/hadoop/output
- 開啟MapReduce 專案
視窗操作 介面中設定 註解 File > new > Map/Reduce? Project>next Project name:sample
Configure Hadoop install directory: /opt/hadoop
=> Finish完成會增加sample專案並切換成MapReduce的視野
- 加入檔案WordCount.java檔
視窗操作 介面中設定 結果 右鍵點選sample專案 > new > file sample >src
File Name: WordCount.java
=> Finish完成後就多了一個WordCount.java檔
- 寫入WordCount.java的內容(code)
- 執行
視窗操作 介面中設定 結果 run > Run Configurations... Main tag :
Name: WordCount
Project: sample
Main class:: WordCount ;Arguments tag :
Program arguments: /opt/hadoop/log /opt/hadoop/test2 => Apply => Runconsole 介面會出現執行結果
- Eclipse是用模擬的方式模擬Hadoop的環境,執行這段程式碼,所以並沒有送上HDFS給Hadoop的job tracker作Map Reduce。 http://localhost:50030 沒有工作運作的紀錄可以證明這點。
- 既然是在本機端上運作,所以給的Program arguments參數 /opt/hadoop/input /opt/hadoop/output 是本機上的目錄。
- 請確認 input 資料夾內有純文字資料,且output資料夾尚未存在(執行後系統會自行建立此資料夾並將結果放入)
- 若Console 介面沒有錯誤訊息,則代表這段程式在主機端運作無誤
09/02/06 17:18:35 INFO jvm.JvmMetrics: Initializing JVM Metrics with processName=JobTracker, sessionId= 09/02/06 17:18:35 WARN mapred.JobClient: Use GenericOptionsParser for parsing the arguments. Applications should implement Tool for the same. 09/02/06 17:18:35 WARN mapred.JobClient: No job jar file set. User classes may not be found. See JobConf(Class) or JobConf#setJar(String). 09/02/06 17:18:35 INFO mapred.FileInputFormat: Total input paths to process : 1 ... 略 ... 09/02/06 17:18:36 INFO mapred.JobClient: Map output bytes=445846 09/02/06 17:18:36 INFO mapred.JobClient: Map input bytes=320950 09/02/06 17:18:36 INFO mapred.JobClient: Combine input records=37943 09/02/06 17:18:36 INFO mapred.JobClient: Map output records=37943 09/02/06 17:18:36 INFO mapred.JobClient: Reduce input records=9284
錯誤排除 :
- input 資料夾內有純文字資料
- output 資料夾尚未存在(執行後系統會自行建立此資料夾並將結果放入)
- 檢查"run configuration" 內的 "Java Application" > "WordCount" 的設定是否正確
- 打包成JAR
視窗操作 介面中設定 結果 File > Export > Java > Runnable JAR file Launch configuration : WordCount - sample
Export destionation : /opt/hadoop/WordCount.jar => Finish => ok/opt/hadoop/下可以找到檔案WordCount.jar
- 最後一個ok在於包入Hadoop的必要library,所以匯出的WordCount.jar 檔大約有4.3MB
- 運行WordCount於HDFS之上
指令:
$ cd /opt/hadoop $ bin/hadoop jar WordCount.jar /user/waue/input /user/waue/out/
- bin/hadoop jar 不可用 -jar,但若是單純用java執行jar, 則要用$ java -jar XXX.jar,不可只用jar
- /user/waue/input /user/waue/out/ 為輸入和輸出的兩個參數,這兩個路徑是HDFS上得路徑,請確認hdfs內的/user/waue/input有純文字檔,且無/user/waue/out/這個資料夾。
- 若已經成功執行過,想再執行第二次,請更換output的資料夾名稱,否則會因資料夾已存在而出現錯誤訊息。
執行畫面
09/02/06 18:13:14 WARN mapred.JobClient: Use GenericOptionsParser for parsing the arguments. Applications should implement Tool for the same. 09/02/06 18:13:14 INFO mapred.FileInputFormat: Total input paths to process : 1 09/02/06 18:13:14 INFO mapred.FileInputFormat: Total input paths to process : 1 09/02/06 18:13:15 INFO mapred.JobClient: Running job: job_200902051032_0009 09/02/06 18:13:16 INFO mapred.JobClient: map 0% reduce 0% 09/02/06 18:13:20 INFO mapred.JobClient: map 100% reduce 0% 09/02/06 18:13:23 INFO mapred.JobClient: Job complete: job_200902051032_0009 09/02/06 18:13:23 INFO mapred.JobClient: Counters: 16 09/02/06 18:13:23 INFO mapred.JobClient: File Systems 09/02/06 18:13:23 INFO mapred.JobClient: HDFS bytes read=320950 09/02/06 18:13:23 INFO mapred.JobClient: HDFS bytes written=130568 09/02/06 18:13:23 INFO mapred.JobClient: Local bytes read=168448 09/02/06 18:13:23 INFO mapred.JobClient: Local bytes written=336932 09/02/06 18:13:23 INFO mapred.JobClient: Job Counters 09/02/06 18:13:23 INFO mapred.JobClient: Launched reduce tasks=1 09/02/06 18:13:23 INFO mapred.JobClient: Launched map tasks=1 09/02/06 18:13:23 INFO mapred.JobClient: Data-local map tasks=1 09/02/06 18:13:23 INFO mapred.JobClient: Map-Reduce Framework 09/02/06 18:13:23 INFO mapred.JobClient: Reduce input groups=9284 09/02/06 18:13:23 INFO mapred.JobClient: Combine output records=18568 09/02/06 18:13:23 INFO mapred.JobClient: Map input records=7868 09/02/06 18:13:23 INFO mapred.JobClient: Reduce output records=9284 09/02/06 18:13:23 INFO mapred.JobClient: Map output bytes=445846 09/02/06 18:13:23 INFO mapred.JobClient: Map input bytes=320950 09/02/06 18:13:23 INFO mapred.JobClient: Combine input records=47227 09/02/06 18:13:23 INFO mapred.JobClient: Map output records=37943 09/02/06 18:13:23 INFO mapred.JobClient: Reduce input records=9284
- http://localhost:50030 會紀錄剛剛運作的工作
DRBL叢集上運行HADOOP
Hadoop Cluster Based on DRBL
- 此篇的目的在於利用DRBL統整一個Cluster,並在上面運行Hadoop。
- 由於DRBL為無碟系統,並非一般的Cluster,因此有些地方需要注意。
零、環境說明
環境中共有七台機器,一台為drbl server,也是hadoop的namenode,其他節點則client 與datanode,如下:
| 名稱 | ip | drbl用途 | hadoop 用途 |
| hadoop | 192.168.1.254 | drbl server | namenode |
| hadoop | 192.168.1.1~12 | drbl client | datanode |
介紹drbl server環境如下:
| debian | etch (4.0) | server - 64 bit |
DRBL為無碟系統,因此只要將drbl server系統與所需服務安裝好,則其他的client網路開機後,就會載入以server為依據的檔案系統,也就是說,只有某些特定資料夾內的內容(如 /etc /root /home /tmp /var ...)會各自不同之外,其他都一樣。舉例若改了server內/etc/hosts檔的,則其他的client都會自動即時一起更改(因為是用NFS mount 上來的)。
因此,只要先在drbl server上完成了一、安裝,二、設定之後,在將其他的client開機然後依照三、操作 就可以了。
一、安裝
1.1 安裝drbl
- 詳見 DRBL的安裝
1.2 安裝 java 6
- 在套件庫裡 /etc/apt/sources.list 加入 non-free 庫以及 backports 網址才能安裝 sun-java6
deb http://free.nchc.org.tw/debian/ etch main contrib non-free deb-src http://free.nchc.org.tw/debian/ etch main contrib non-free deb http://security.debian.org/ etch/updates main contrib non-free deb-src http://security.debian.org/ etch/updates main contrib non-free deb http://www.backports.org/debian etch-backports main non-free deb http://free.nchc.org.tw/drbl-core drbl stable
- 安裝key及java6
$ wget http://www.backports.org/debian/archive.key $ sudo apt-key add archive.key $ apt-get update $ apt-get install sun-java6-bin sun-java6-jdk sun-java6-jre
1.3 安裝 Hadoop 0.18.3
$ cd /opt $ wget http://ftp.twaren.net/Unix/Web/apache/hadoop/core/hadoop-0.18.3/hadoop-0.18.3.tar.gz $ tar zxvf hadoop-0.18.3.tar.gz
1.4 設定使用者
$ su - $ addgroup hdfsgrp $ adduser --ingroup hdfsgrp hdfsadm $ chown -R hdfsadm:hdfsgrp /opt/hadoop-0.18.3 $ chmod -R 775 /opt/hadoop-0.18.3 $ su - hdfsadm $ cd /opt/hadoop $ ln -sf hadoop-0.18.3 hadoop
二、設定 Hadoop
- 在 /etc/bash.bashrc 的最末加入 以下資訊
PATH=$PATH:/opt/drbl/bin:/opt/drbl/sbin export JAVA_HOME=/usr/lib/jvm/java-6-sun export HADOOP_HOME=/opt/hadoop/
- 載入設定值
$ source /etc/bash.bashrc
- 編輯 /etc/hosts 把下面內容貼在最後
192.168.1.254 gm2.nchc.org.tw 192.168.1.1 hadoop101 192.168.1.10 hadoop110 192.168.1.11 hadoop111 192.168.1.2 hadoop102 192.168.1.3 hadoop103 192.168.1.4 hadoop104 192.168.1.5 hadoop105 192.168.1.6 hadoop106 192.168.1.7 hadoop107 192.168.1.8 hadoop108 192.168.1.9 hadoop109
- 編輯 /opt/hadoop-0.18.3/conf/hadoop-env.sh
-
hadoop-0.18.3/conf/hadoop-env.sh
old new 6 6 # remote nodes. 7 7 # The java implementation to use. Required. 8 # export JAVA_HOME=/usr/lib/j2sdk1.5-sun 8 export JAVA_HOME=/usr/lib/jvm/java-6-sun 9 export HADOOP_HOME=/opt/hadoop 10 export HADOOP_CONF_DIR=$HADOOP_HOME/conf 11 export HADOOP_LOG_DIR=/home/hdfsadm/hdfs/logs 12 export HADOOP_PID_DIR=/home/hdfsadm/hdfs/pids 9 13 10 14 # Extra Java CLASSPATH elements. Optional. 11 15 # export HADOOP_CLASSPATH=
-
- 編輯 /opt/hadoop-0.18.3/conf/hadoop-site.xml
-
hadoop-0.18.3/conf/hadoop-site.xml
old new 4 4 <!-- Put site-specific property overrides in this file. --> 5 5 <configuration> 6 6 <property> 7 <name>fs.default.name</name> 8 <value>hdfs://gm2.nchc.org.tw:9000/</value> 9 <description> 10 The name of the default file system. Either the literal string 11 "local" or a host:port for NDFS. 12 </description> 13 </property> 14 <property> 15 <name>mapred.job.tracker</name> 16 <value>hdfs://gm2.nchc.org.tw:9001</value> 17 <description> 18 The host and port that the MapReduce job tracker runs at. If 19 "local", then jobs are run in-process as a single map and 20 reduce task. 21 </description> 22 </property> 23 <property> 24 <name>hadoop.tmp.dir</name> 25 <value>/tmp/hadoop/hadoop-${user.name}</value> 26 <description>A base for other temporary directories.</description> 27 </property> 7 28 </configuration>
-
- 編輯 /opt/hadoop/conf/slaves
192.168.1.1 192.168.1.2 192.168.1.3 192.168.1.4 192.168.1.5 192.168.1.6 192.168.1.7 192.168.1.8 192.168.1.9 192.168.1.10 192.168.1.11 192.168.1.12
三、操作
3.1 開啟DRBL Client
- 將所有的 client 開啟,並且如下
****************************************************** NIC NIC IP Clients +------------------------------+ | DRBL SERVER | | | | +-- [eth2] 140.110.X.X +- to WAN | | | +-- [eth1] 192.168.1.254 +- to clients group 1 [ 6 clients, their IP | | from 192.168.1.1 - 192.168.1.12] +------------------------------+ ****************************************************** Total clients: 12 ******************************************************
3.2 設定ssh
- 編寫 /etc/ssh/ssh_config
StrictHostKeyChecking no
- 執行
$ su - $ /opt/drbl/sbin/drbl-useradd -s hdfsadm hdfsgrp $ su - hdfsadm $ ssh-keygen -t rsa -b 1024 -N "" -f ~/.ssh/id_rsa $ cp ~/.ssh/id_rsa.pub ~/.ssh/authorized_keys $ /etc/init.d/ssh restart
- 正確無誤則可免密碼登入
3.2.1 dsh
$ sudo apt-get install dsh $ mkdir -p .dsh $ for ((i=1;i<=12;i++)); do echo "192.168.1.$i" >> .dsh/machines.list; done
- 測試並執行
$ dsh -a hostname $ dsh -a source /etc/bash.bashrc
3.3 啟動 Hadoop
- 啟動
$ cd /opt/hadoop $ bin/hadoop namenode -format $ bin/start-all.sh
3.4 Hadoop 測試範例
- 運作WordCount以測試
$ mkdir input $ cp *.txt input/ $ bin/hadoop dfs -put input input $ bin/hadoop jar hadoop-*-examples.jar wordcount input ouput
- 執行畫面:
hadoop:/opt/hadoop# bin/hadoop jar hadoop-*-examples.jar wordcount input ouput 09/02/26 06:16:34 INFO mapred.FileInputFormat: Total input paths to process : 4 09/02/26 06:16:34 INFO mapred.FileInputFormat: Total input paths to process : 4 09/02/26 06:16:35 INFO mapred.JobClient: Running job: job_200902260615_0001 09/02/26 06:16:36 INFO mapred.JobClient: map 0% reduce 0% 09/02/26 06:16:39 INFO mapred.JobClient: map 80% reduce 0% 09/02/26 06:16:40 INFO mapred.JobClient: map 100% reduce 0% 09/02/26 06:16:50 INFO mapred.JobClient: Job complete: job_200902260615_0001 09/02/26 06:16:50 INFO mapred.JobClient: Counters: 16 09/02/26 06:16:50 INFO mapred.JobClient: File Systems 09/02/26 06:16:50 INFO mapred.JobClient: HDFS bytes read=267854 09/02/26 06:16:50 INFO mapred.JobClient: HDFS bytes written=100895 09/02/26 06:16:50 INFO mapred.JobClient: Local bytes read=133897 09/02/26 06:16:50 INFO mapred.JobClient: Local bytes written=292260 09/02/26 06:16:50 INFO mapred.JobClient: Job Counters 09/02/26 06:16:50 INFO mapred.JobClient: Launched reduce tasks=1 09/02/26 06:16:50 INFO mapred.JobClient: Rack-local map tasks=5 09/02/26 06:16:50 INFO mapred.JobClient: Launched map tasks=5 09/02/26 06:16:50 INFO mapred.JobClient: Map-Reduce Framework 09/02/26 06:16:50 INFO mapred.JobClient: Reduce input groups=8123 09/02/26 06:16:50 INFO mapred.JobClient: Combine output records=17996 09/02/26 06:16:50 INFO mapred.JobClient: Map input records=6515 09/02/26 06:16:50 INFO mapred.JobClient: Reduce output records=8123 09/02/26 06:16:50 INFO mapred.JobClient: Map output bytes=385233 09/02/26 06:16:50 INFO mapred.JobClient: Map input bytes=265370 09/02/26 06:16:50 INFO mapred.JobClient: Combine input records=44786 09/02/26 06:16:50 INFO mapred.JobClient: Map output records=34913 09/02/26 06:16:50 INFO mapred.JobClient: Reduce input records=8123 hadoop:/opt/hadoop#
- http://gm2.nchc.org.tw:50030/
- 網頁中可以看到剛剛有在工作的node數
gm2 Hadoop Map/Reduce Administration
State: RUNNING
Started: Tue Mar 17 16:22:46 EDT 2009
Version: 0.18.3, r736250
Compiled: Thu Jan 22 23:12:08 UTC 2009 by ndaley
Identifier: 200903171622
Cluster Summary
Maps Reduces Total Submissions Nodes Map Task Capacity Reduce Task Capacity Avg. Tasks/Node 0 0 1 9 18 18 4.00
Running Jobs
Running Jobs none
Completed Jobs
Completed Jobs Jobid User Name Map % Complete Map Total Maps Completed Reduce % Complete Reduce Total Reduces Completed job_200903171622_0001 hdfsadm wordcount 100.00% 5 5 100.00% 1 1
- 網頁中可以看到剛剛有在工作的node數
3.5 停止hadoop
$ bin/stop-all.sh
3.6 重新建立 hadoop
$ bin/stop-all.sh $ dsh -a rm -rf ~/hdfs/logs/* ~/hdfs/pids/* /tmp/hadoop/* $ bin/hadoop namenode -format $ bin/start-all.sh
四、操作
4.1 帳號
- 增加一個hadoop帳號huser,使之可以在hdfs上自己的目錄內進行存取瀏覽的操作
1. 在drbl系統新增帳號 huser
$ su - $ /opt/drbl/sbin/drbl-useradd -s huser huser
2. 用hdfs的superuser(此篇文章為hdfsadm)在hdfs上建立資料夾
$ su - hdfsadm $ /opt/hadoop/bin/hadoop dfs -mkdir /user/huser
3. 用superuser 設定hdfs上該資料夾的權限與擁有者
$ /opt/hadoop/bin/hadoop dfs -chown -R huser /user/huser $ /opt/hadoop/bin/hadoop dfs -chmod -R 775 /user/huser
4. 測試:用huser瀏覽或寫入檔案
<root>$ su - huser <huser>$ cd /opt/hadoop/ <huser>$ /opt/hadoop/bin/hadoop dfs -put input /user/huser/input <huser>$ /opt/hadoop/bin/hadoop dfs -ls /user/huser/input
4.2 多帳號執行
- 測試兩個user: rock , waue 同時執行,沒有問題
bin/hadoop jar hadoop-*-examples.jar wordcount input/ ouput/
網頁結果:
Completed Jobs
| Completed Jobs | ||||||||||
| Jobid | User | Name | Map % Complete | Map Total | Maps Completed | Reduce % Complete | Reduce Total | Reduces Completed | ||
| job_200903061742_0001 | waue | wordcount | 100.00% | 1 | 1 | 100.00% | 1 | 1 | ||
| job_200903061742_0002 | rock | wordcount | 100.00% | 1 | 1 | 100.00% | 1 | 1 | ||
| job_200903061742_0003 | waue | wordcount | 100.00% | 1 | 1 | 100.00% | 1 | 1 | ||
Failed Jobs
五、參考資料
六、問題排解
- drbl似乎安裝不順
drblsrv -i 出現以下錯誤訊息
Kernel 2.6 was found, so default to use initramfs. The requested kernel "" 2.6.18-6-amd64 kernel files are NOT found in /tftpboot/node_root/lib/modules/s and /tftpboot/node_root/boot in the server! The necessary modules in the network initrd can NOT be created! Client will NOT remote boot correctly! Program terminated! Done!
原因: apt 的鏡像站台沒有複製到資料因此無法安裝新kernel,導致出現問題
- Hadoop 空間問題
hdfsadm@hadoop102:~$ df /tmp Filesystem 1K-blocks Used Available Use% Mounted on tmpfs 1018360 712 1017648 1% /tmp hdfsadm@hadoop102:~$ df / Filesystem 1K-blocks Used Available Use% Mounted on 192.168.1.254:/tftpboot/node_root 28834720 20961600 6408384 77% /
datanode hadoop102的空間大小指稱有0.98G的空間,因此研判datanode的空間大小為hadoop.tmp.dir所設定的目錄剩餘空間
- 如何增加drbl_hadoop 模式下 datanode的可用空間
- 將硬碟mount起來到/hdfs_data資料夾
- 將hadoop.tmp.dir設在各個datanode的 /hdfs_data中
使用Eclipse開發MapReduce程式
作者 公司 日期 陳威宇 國家高速網路中心 2009/02/02
一、準備
- 系統 :
- Ubuntu 8.10
- Hadoop 0.18.3
- 下載安裝方法於 2.2 說明
- 開發工具 :
- Eclipse 3.2.2
指令 註解 $ apt-get install eclipse 安裝eclipse
- java 6
指令 註解 $ sudo apt-get purge java-gcj-compat 由於版權關係,ubuntu預設安裝的gcj為java的模擬軟體,請移除 $ sudo apt-get install sun-java6-bin sun-java6-jdk sun-java6-jre sun-java6-plugin 安裝 Sun版Java
- 設定環境變數
- 開啟bash.bashrc 貼上環境變數設定(sudo gedit /etc/bash.bashrc),在最後一行貼入下面內容
export JAVA_HOME=/usr/lib/jvm/java-6-sun export HADOOP_HOME=/opt/hadoop/ export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
- 由前面設定後,環境參數如下表
- 開啟bash.bashrc 貼上環境變數設定(sudo gedit /etc/bash.bashrc),在最後一行貼入下面內容
Name Path Hadoop Home /opt/hadoop/ Java Home /usr/lib/jvm/java-6-sun
二、安裝與設定 Hadoop
Hadoop 是Apache所維護的自由軟體專案,而HDFS (Hadoop Distributed File System)是指Hadoop檔案系統,因此安裝的時候我們安裝配置了Hadoop專案,但操作時,尤其指Hadoop系統操作,我們會用HDFS來稱呼。因此,整個邏輯可以看成,我們在Linux系統內安裝配置了Hadoop,執行之後,它會產生一個新的分散式的磁碟系統,也就是HDFS,架構在Linux之內。由於是分散式系統,意味著他可以橫跨多台Linux所形成的叢集系統,並聯其磁碟空間。不過此篇的目的為撰寫MapReduce程式,所以在此示範的設定為HDFS運作於單一的本機系統內。
2.1 幫User產生ssh金鑰
指令 註解 $ ssh-keygen -t rsa -P "" 產生免密碼的ssh金鑰 $ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys 匯入免檢查名單 $ ssh localhost 測試登入是否不用密碼 $ exit 完成離開
2.2 安裝 Hadoop
指令 註解 $ wget http://ftp.twaren.net/Unix/Web/apache/hadoop/core/hadoop-0.18.3/hadoop-0.18.3.tar.gz 下載原始碼 $ sudo tar -zxvf hadoop-0.18.3.tar.gz -C /opt/ 解壓縮 $ sudo chown -R waue:waue /opt/hadoop-0.18.3 改權限 $ sudo ln -sf /opt/hadoop-0.18.3 /opt/hadoop 建目錄連結 $ cd /opt/hadoop
2.3 設定
- 修改 hadoop-env.sh 檔 ($ gedit /opt/hadoop/conf/hadoop-env.sh )
- 修改內容:
-
/opt/hadoop/conf/hadoop-env.sh
old new 8 8 # The java implementation to use. Required. 9 # export JAVA_HOME=/usr/lib/j2sdk1.5-sun 9 export JAVA_HOME=/usr/lib/jvm/java-6-sun 10 export HADOOP_HOME=/opt/hadoop 11 export HADOOP_LOG_DIR=$HADOOP_HOME/logs 12 export HADOOP_SLAVES=$HADOOP_HOME/conf/slaves
-
- 修改內容:
- 修改 hadoop-site.xml 檔($ gedit HADOOP_HOME/conf/hadoop-site.xml)
- 整段貼上:
<configuration> <property> <name>fs.default.name</name> <value>hdfs://localhost:9000/</value> <description> </description> </property> <property> <name>mapred.job.tracker</name> <value>hdfs://localhost:9001/</value> <description> </description> </property> <property> <name>mapred.map.tasks</name> <value>1</value> <description> define mapred.map tasks to be number of slave hosts </description> </property> <property> <name>mapred.reduce.tasks</name> <value>1</value> <description> define mapred.reduce tasks to be number of slave hosts </description> </property> <property> <name>dfs.replication</name> <value>1</value> </property> </configuration>
- 整段貼上:
2.4 啟動 HDFS
- 格式化HDFS (Hadoop Distributed File System)
指令 $ cd $HADOOP_HOME $ bin/hadoop namenode -format
- 執行結果:
09/02/03 18:08:59 INFO dfs.NameNode: STARTUP_MSG: /************************************************************ STARTUP_MSG: Starting NameNode STARTUP_MSG: host = vPro/140.110.138.193 STARTUP_MSG: args = [-format] STARTUP_MSG: version = 0.18.3 STARTUP_MSG: build = https://svn.apache.org/repos/asf/hadoop/core/branches/branch-0.18 -r 736250; compiled by 'ndaley' on Thu Jan 22 23:12:08 UTC 2009 ************************************************************/ 09/02/03 18:08:59 INFO fs.FSNamesystem: fsOwner=waue,waue,adm,dialout,cdrom,floppy,audio,dip,video,plugdev,fuse,lpadmin,admin,sambashare 09/02/03 18:08:59 INFO fs.FSNamesystem: supergroup=supergroup 09/02/03 18:08:59 INFO fs.FSNamesystem: isPermissionEnabled=true 09/02/03 18:08:59 INFO dfs.Storage: Image file of size 78 saved in 0 seconds. 09/02/03 18:08:59 INFO dfs.Storage: Storage directory /tmp/hadoop-waue/dfs/name has been successfully formatted. 09/02/03 18:08:59 INFO dfs.NameNode: SHUTDOWN_MSG: /************************************************************ SHUTDOWN_MSG: Shutting down NameNode at vPro/140.110.138.193 ************************************************************/
- 啟動HDFS
指令 $ bin/start-all.sh
- 執行結果:
starting namenode, logging to /opt/hadoop/logs/hadoop-waue-namenode-vPro.out localhost: starting datanode, logging to /opt/hadoop/logs/hadoop-waue-datanode-vPro.out localhost: starting secondarynamenode, logging to /opt/hadoop/logs/hadoop-waue-secondarynamenode-vPro.out starting jobtracker, logging to /opt/hadoop/logs/hadoop-waue-jobtracker-vPro.out localhost: starting tasktracker, logging to /opt/hadoop/logs/hadoop-waue-tasktracker-vPro.out
- 在瀏覽器URL列輸入以下三個網址,若都有畫面則成功啟動
網址 說明 http://localhost:50030 Map/Reduce? Administration http://localhost:50060 Task Tracker StatusTask Tracker Status http://localhost:50070 NameNode
2.5 除錯
- 如果你的系統在啟動的時候有錯誤發生,則請停止Hadoop並完全移除Hadoop產生的中間資料,再重新開始
指令 $ cd $HADOOP_HOME $ bin/stop-all.sh $ rm -rf /tmp/* 檢查 2.3 內容,重新執行2.4內容
三、 Hadoop的Eclipse-Plugin安裝與操作
Elipse是Sun公司所開發,是個很知名的Java程式語言開發程式,雖然Hadoop也是用java所開發,但要讓eclipse認得Hadoop的API、編譯器、並執行程式,需要調校的地方很多,步驟也很繁瑣。IBM發佈了一個Eclipse插件-IBM MapReduce Tools for Eclipse,通過該插件,開發者可以在Eclipse上創建MapReduce應用程序。以下我們就來示範如何安裝這個Hadoop的eclipse-plugin。
3.1 eclipse 3.3 以上版本(有bug)
- 安裝IBM MapReduce tool
指令 $ sudo cp /opt/hadoop-0.18.3/contrib/eclipse-plugin/hadoop-0.18.3-eclipse-plugin.jar /usr/lib/eclipse/plugins/
ps : 上述的方法需eclipse 3.3 以上 搭配 hadoop 0.17 以上版本。
- 在系統視窗中,右鍵點選eclipse圖示,在指令欄加入參數以增加穩定度
/usr/bin/eclipse -vmargs -Xmx512M
- 啟動eclipse,從視窗介面操作:
視窗操作 介面中設定 註解 File > New > Project 看到 MapReduce category 檢查是否安裝IBM MapReduce tool成功 Window > Preferences > java> compiler 設定 compiler compliance level 為 1.6 更改java編譯器為1.6 以上,否則會出現一堆error
- 開啟hadoop 專案
視窗操作 介面中設定 註解 File > new > Map/Reduce? Project>next Project name:sample
Configure Hadoop install directory => /opt/hadoop設定專案名稱及hadoop的家目錄
- 完成後 Project Explorer可以看到 sample的專案列出
- 讓Eclipse連接到HDFS
視窗操作 介面中設定 註解 Window > Show View > Other... > MapReduce Tools MapReduce locations 開啟MapReduce編譯環境,完成後右下方視窗會多一個藍色的大象圖示 點選右下藍色大象圖示 location name : test
Host:localhost
M/R Master: Port:9001
DFS Master: Use Use M/R Master host:V
Port:9000設定對應到 hadoop-site.xml檔
- mapred.job.tracker 的設定若為 hdfs://ubuntu:9010/ ,則M/R Master的設定為 host:ubuntu , Port:9010 ,DFS Master的設定則對應到 fs.default.name
- 注意 hdfs必須已經啟動,否則無法點選finish鍵
- 完成後在Project Explorer可以看到DFS Locations出現
- 2009/2/5 測試到目前為止,用最新版的eclipse 3.4 搭配 0.18.3 或 0.19.0 版的 hadoop plugin,在"run as" => "run on hadoop" 都無法正常運作(應該要彈出選擇server location的視窗),此問題在2008/7/31就被發現並已被發佈於 (HADOOP-3744) Eclipse Plugin does not work with Eclipse Ganymede (3.4),目前尚待解決。
3.2 eclipse 3.2 以下版本
- 安裝IBM MapReduce tool
eclipse 3.2 以前的版本必須要去IBM官方網站下載mapReduce_tools.zip,解壓縮後將資料夾複製到$eclipse/plugins/才可以運作
- 在系統視窗中,右鍵點選eclipse圖示,在指令欄加入參數以增加穩定度
/usr/bin/eclipse -vmargs -Xmx512m
- 啟動eclipse,從視窗介面操作:
視窗操作 介面中設定 註解 File > New > Project 看到 MapReduce category 檢查是否安裝IBM MapReduce tool成功 Window > Preferences > java> compiler 設定 compiler compliance level 為 5.0 更改java編譯器為5.0以上,否則會出現一堆error
- 啟動eclipse,從視窗介面操作
視窗操作 介面中設定 註解 File > new > project > map-reduce project > next > project name : sample
use default location : V
use default Hadoop : V
> Finish
設定專案預設值
- 讓Eclipse連接到HDFS
視窗操作 介面中設定 註解 Window > Show View > Other... > MapReduce Tools > MapReduce Servers MapReduce Servers 開啟MapReduce編譯環境,完成後右下方視窗會多一個藍色的大象圖示 點選藍色大象圖示 Server name : any_you_want
Hostname : localhost
Installation directory: /opt/hadoop/
Username : waue
開啟Hadoop伺服器,若有任何的密碼提示對話框出現,請填入登入Linux的系統使用者之密碼
四、用Eclipse編譯MapReduce範例程式
在這個範例中,我們先上傳一個純文字檔到HDFS內,這個檔案的副檔名為何不重要,只要內文為純文字檔即可,簡單的可以直接把Readme檔上傳上去,但為了突顯MapReduce的威力,當然是放越大的檔案上去給Hadoop操一下越好囉!接著示範如何用Eclipse來編寫MapReduce的程式,並執行編譯的動作。
1. 上傳字典檔,以供WordCount程序作字數統計的來源檔
指令 $ cd /opt/hadoop/ $ wget xxx/132.txt $ bin/hadoop dfs -mkdir input $ bin/hadoop dfs -put 132.txt input $ bin/hadoop dfs -ls Found 1 items /user/waue/input <dir> 2008-05-23 15:15 rwxr-xr-x waue supergroup
2. 在eclipse中新增程式碼
於Eclipse左邊的Project explorer內,我們可以看到剛剛設定的工作目錄sample。 我們新增一個範例程式:
視窗操作 介面中設定 註解 Project explorer內,右鍵點選 sample> new > file file name : WordCount.java 新增一個WordCount.java檔案
3. 撰寫程式
貼上 WordCount.java 的內容。
4. 執行
視窗操作 介面中設定 註解 Project explorer內,右鍵點選 WordCount.java > run as ... > choose an existing server from the list below finish 執行MapReduce
5. 執行畫面會出現在右下方的視窗:console
6. Hadoop的運算結果置於HDFS內的檔案中,要觀看結果內容,有以下三種方法
- 用瀏覽器: 網址輸入 http://localhost:50070,點檔案目錄,
- 直接用HDFS的指令秀出結果內容
- 用指令將輸出結果從HDFS內複製到本機資料夾內再觀看
7. 執行期間或執行結束,都可以到以下網址來看執行過程及結果
網址 說明 http://localhost:50030 hadoop-master http://localhost:50060 hadoop-jobTracker http://localhost:50070 hadoop-fileSystem
五、 參考
- NCHC Cloud Technique Develop Group
- IBM Map-Reduce
- Cloud9
- Runing Hadoop
Linux 主機作Gateway功能
用一台可以連外的主機當Gateway,其他的電腦則用這台主機建構的DHCP來連到網路,已經是很多人家裡的網路配置方法。之前大部分都用現成的filmware 來作,或用有圖形介面的工具來達成,不過這次分享的是希望完全用指令來實做。
動機是部屬好的諸台主機已經是drbl環境了,因此drbl server有兩張網卡並對外,而要當client的只連接到內部區網中。雖然drbl client是不需要內建os的,不過考慮到有朝一日還是會用到內建的硬碟開機,所以還是把他的硬碟灌一灌。不過麻煩的是client的網路都已經接在內部網域了,在不重改接線配置的情況下,最簡單的方法還是讓drbl server這台當gateway,client透過server連到外部網路把軟體裝好在硬碟之後,再用drbl server用clone zilla功能把裝好的client 備援起來。由於是最簡單的設定,因此也不搞dhcp了,直接用static ip 定址,搭配NAT的ip_forward,讓內部的機器可以把封包送出去。
環境
- drbl server (Debian Etch)
兩張網卡,eth1對內,eth2對外:
| eth1 | 192.168.1.254 | 內部區網的gateway address |
| eth2 | 140.110.111.222 | 對外連接的網卡設定 |
- drbl client
| eth1 | 192.168.1.12 | 固定位址 |
server 設定
網卡設定
- vim /etc/network/interface
auto lo iface lo inet loopback auto eth2 auto eth1 iface eth2 inet static address 140.110.111.222 netmask 255.255.255.055 gateway 140.110.111.254 dns-nameservers 140.110.16.1 dns-search nchc.org.tw iface eth1 inet static address 192.168.1.254 netmask 255.255.255.0
重新啟動網路:
$ /etc/init.d/network restart
DNS
安裝bind就可以解析域名了(iptables是之後有用到順便裝)
$ apt-get install bind iptables
NAT
打開ip forward
$ echo 1 > /proc/sys/net/ipv4/ip_forward
讓防火牆開啟NAT功能,由於是固定ip,用snat較有效率
$ iptables -t nat -A POSTROUTING -o eth2 -j SNAT --to 140.110.111.222
PS:若對外ip是用pppoe的方式,或不是固定ip,則動態配置用MASQUERADE比較不麻煩,壞處是較無效率
$ iptables -t nat -A POSTROUTING -o eth2 -j MASQUERADE
重開機也有效的NAT設定
以上的指令只是暫時有效,但一重開機後又回覆預設值,因此修改ip forward預設值才是長久之計:
- vim /etc/sysctl.conf
net.ipv4.conf.default.forwarding=1 # 把註解拿掉
- vim /etc/network/if-up.d/iptables
#!/bin/sh # Set up firewall rules. /sbin/iptables-restore /etc/network/iptables.rules
- make the script executable.
# chmod 755 /etc/network/if-up.d/iptables # iptables-save > /etc/network/iptables.rules
Client設定
Client的設定很簡單,只要設定正確的區域網路位址,gateway設定到server的對內網卡ip就可以了,連dns都不用設。
- vim /etc/network/interface
auto lo iface lo inet loopback auto eth1 iface eth1 inet static address 192.168.1.12 netmask 255.255.255.0 gateway 192.168.1.254
如果server有用dhcp的話,設定更簡單了:
auto lo iface lo inet loopback auto eth1 iface eth1 inet dhcp
Trac on Ubuntu
緣由
由於Jazz大力推薦,使用Trac已經好一陣子,覺得是一個不錯的文件工作管理系統。不過都用Jazz架好的系統,也想要自己試一下怎麼安裝架設。除此之外,trac的預設CSS還有更符合個人瀏覽習慣的改進空間,加上一些trac的plug in也想試試看。 我的安裝環境於 Ubuntu 8.04 & trac 0.11,參考主要是官方網站:
雖然官網介紹得很詳盡,不過還是有些小細節要注意,安裝方法如下:
環境參數
查看 Ubuntu 機器資訊
$ cat /etc/lsb-release DISTRIB_ID=Ubuntu DISTRIB_RELEASE=8.04 DISTRIB_CODENAME=hardy DISTRIB_DESCRIPTION="Ubuntu 8.04.1"
環境路徑
以下內容會用到的路徑統一在此作說明解釋
| 名稱 | 目錄 |
| Trac安裝路徑 | /usr/share/trac |
| Trac專案根目錄 | /var/lib/trac |
| Trac專案子目錄 | /var/lib/trac/waue |
| 版本控制根目錄 | /var/lib/svn |
| 網址 | http://gm1.nchc.org.tw/waue |
- Trac 安裝路徑 包含了原始的trac內容,以及程式碼,然而當你要用trac開一個專案時,Trac會要你裝在其他的路徑以做分離,免得原始的Trac跟你的專案搞混在一起,因此Trac專案根目錄就是你之後會把專案放的目錄囉!
Trac 0.11 安裝
1. 軟體套件
- 安裝 apache, setuptools 及一些 libraries:
$ sudo apt-get install apache2 libapache2-mod-python \
libapache2-svn python-setuptools subversion python-subversion
- 安裝 Easy_install
$ sudo mkdir /opt/setuptools $ cd /opt/setuptools/ $ sudo svn co http://svn.python.org/projects/sandbox/branches/setuptools-0.6/ $ cd setuptools-0.6/ $ sudo python setup.py install
- 用easy_install安裝trac (當然也可以直接用apt-get 安裝,只是目前是trac 0.10版)
$ sudo easy_install Trac
2. 建立 Trac 專案根目錄
- 建立 Trac 專案根目錄並設定apache有讀寫權限
$ sudo mkdir /var/lib/trac $ sudo chown www-data:www-data /var/lib/trac
3. 整合trac到 Apache2
設定trac整合到apache的步驟
- 先創立一個trac模型
$ sudo vi /etc/apache2/sites-available/trac
- 填入此模型的內容
<VirtualHost *>
ServerAdmin waue0920@gmail.com
ServerName gm1.nchc.org.tw
DocumentRoot /var/www
ErrorLog /var/log/apache2/error.trac.log
CustomLog /var/log/apache2/access.trac.log combined
Alias /template/chrome/common /usr/share/trac/htdocs
<Location /waue>
SetHandler mod_python
PythonInterpreter main_interpreter
PythonHandler trac.web.modpython_frontend
PythonOption TracEnvParentDir /var/lib/trac
PythonOption TracUriRoot /waue
PythonOption PYTHON_EGG_CACHE /var/www/.python-eggs
</Location>
# use the following for one authorization for all projects
# (names containing "-" are not detected):
<LocationMatch "/waue/[[:alnum:]]+/login">
AuthType Basic
AuthName "trac"
AuthUserFile /etc/apache2/dav_svn.passwd
Require valid-user
</LocationMatch>
</VirtualHost>
- 建立python在apache2上用到的cache目錄
$ sudo mkdir /var/www/.python-eggs $ sudo chown www-data.www-data /var/www/.python-eggs
- 然後,取消default模板,換成剛剛的trac模板
$ sudo a2dissite default $ sudo a2ensite trac
4. SVN
讓trac有版本控制的功能。
- 建立 /var/lib/svn 目錄來做同步的資料儲存庫,並用指令 svnadmin create 開啟svn專案
$ sudo mkdir /var/lib/svn $ sudo svnadmin create /var/lib/svn/waue $ sudo chown -R www-data /var/lib/svn $ sudo chown -R www-data /usr/share/trac
修改 /etc/apache2/mods-available/dav_svn.conf 以設定svn目錄參數
<Location /svn>
# Uncomment this to enable the repository,
DAV svn
# Set this to the path to your repository
SVNParentPath /var/lib/svn
</Location>
- ps: 關於svn detail請見 References: Commands populate files into SVN repository
5. 創建專案並啟動 Trac
- 用指令trac-admin /var/lib/trac/waue initenv,在 /var/lib/trac根目錄中建立一個waue專案
$ sudo trac-admin /var/lib/trac/waue initenv
- 執行trac-admin這個指令會有query詢問環境參數如何設定:
- Project Name [My Project]> waue
- Database connection string [sqlite:db/trac.db]> [Enter鍵]
- Repository type [svn]> [Enter鍵]
- Path to repository /path/to/repos> /var/lib/svn/waue
- Path to repository /path/to/repos> 這行要設定的是svn的路徑,設錯會有warning.
- 接著設定權限並重新啟動apache2
$ sudo chown -R www-data /var/lib/trac $ sudo /etc/init.d/apache2 reload
- 在瀏覽器輸入你的網址http://localhost/waue就可以看到Trac網頁內容囉! http://localhost/waue
ps: 更完整的Mod_Python設定,可以看 TracModPython
6. Plugin
安裝好用的套件
apt-get trac plugins
$ sudo apt-get install build-essential graphviz htmldoc enscript
Easy_install Trac plugins
- 官網介紹區
$ sudo easy_install http://svn.edgewall.org/repos/genshi/trunk/ $ sudo easy_install http://trac-hacks.org/svn/accountmanagerplugin/trunk $ sudo easy_install http://trac-hacks.org/svn/customfieldadminplugin/0.11 $ sudo easy_install http://trac-hacks.org/svn/eclipsetracplugin/tracrpcext/0.10 $ sudo easy_install http://trac-hacks.org/svn/iniadminplugin/0.11 $ sudo easy_install http://trac-hacks.org/svn/masterticketsplugin/0.11 $ sudo easy_install http://trac-hacks.org/svn/pagetopdfplugin/0.10/ $ sudo easy_install http://trac-hacks.org/svn/progressmetermacro/0.11 $ sudo easy_install http://trac-hacks.org/svn/ticketdeleteplugin/0.11 $ sudo easy_install http://trac-hacks.org/svn/tracwysiwygplugin/0.11 $ sudo easy_install http://wikinotification.ufsoft.org/svn/trunk
- jazz推薦區
//Redirect $ sudo easy_install http://svn.ipd.uka.de/repos/javaparty/JP/trac/plugins/redirect-0.11/ //AztechCalendar $ cd /opt/setuptools/ $ sudo svn co http://trac-hacks.org/svn/calendarplugin $ cd calendarplugin/0.10 $ python setup.py bdist_egg $ sudo easy_install dist/AztechCalendar*.egg
7. Adding Authentication
做了權限設定之後,才能夠登入trac,編輯文章等等..
權限設定
- 用 htpasswd -c 來創建 password 檔:
$ htpasswd -c /etc/apache2/dav_svn.passwd admin New password: <type password> Re-type new password: <type password again> Adding password for user admin
- 增加使用者也是用htpasswd,但不要加參數 "-c"
$ htpasswd /etc/apache2/dav_svn.passwd waue New password: <type password> Re-type new password: <type password again> Adding password for user waue
- 設定Trac的login到Apache的模型($ sudo vi /etc/apache2/sites-available/trac):
<Location "/trac/login"> AuthType Basic AuthName "Trac" AuthUserFile /etc/apache2/dav_svn.passwd Require valid-user </Location>
多個專案
- 如果你有很多的project要管理,可以用下面的方法來設定多個專案:
<LocationMatch "/trac/[^/]+/login"> AuthType Basic AuthName "Trac" AuthUserFile /etc/apache2/dav_svn.passwd Require valid-user </LocationMatch>
更安全的作法
- 安全因素考量,建立SSL連線;或AuthType用「Digest」代替 「Basic」. 更多 Apache HTTPD documentation 。
<Location "/trac/login">
LoadModule auth_digest_module /usr/lib/apache2/modules/mod_auth_digest.so
AuthType Digest
AuthName "trac"
AuthDigestDomain /trac
AuthUserFile /etc/apache2/dav_svn.passwd
Require valid-user
</Location>
- 新增 .htpasswd file with htdigest instead of htpasswd as follows:
$ sudo htdigest /etc/apache2/dav_svn.passwd trac admin
- where the "trac" parameter above is the same as AuthName above ("Realm" in apache-docs).
$ sudo chown www-data /etc/apache2/dav_svn.passwd
-
/var/lib/trac/waue/conf/trac.ini
old new 24 24 [header_logo] 25 alt = (please configure the [header_logo] section in trac.ini)26 height = -1 27 link = 28 src = site/your_project_logo.png29 width = -1 25 alt = "Waue Trac" 26 height = -1 27 link = http://gm1.nchc.org.tw/waue/waue 28 src = common/trac_banner.png 29 width = -1
Trac的專案移植
昨天跟Jazz討論到Trac的多個專案管理的問題,於是就把trac主機上grid專案打包後傳給我,並把移植的方法寫給我,我調整成我環境的路徑之後並紀錄於下
$ cd /var/lib/trac $ sudo tar zxvf trac_template.tar.gz $ sudo trac-admin /var/lib/trac/template upgrade $ cd /etc/apach2/site-enabled $ ln -s /forge/trac_pool/template/apache2_conf/template.conf $ /etc/init.d/apache2 reload
- 無法相同於trac.nchc.org.tw,是因還需要安裝以下的plugin:
- AztechCalendar
- SvnAuthzAdminPlugin
- TracWebAdmin
- TracAccountManager
- Redirect
- 目前遇到的問題是,grid專案的內容都不見了,是否存到資料庫的資料沒有放進來或我參數設定不對...畫面如下
Trac and Subversion
官網的svn設定落落長 Trac and Subversion
其實只要修改 conf/trac.ini 檔的repository_dir的參數內容為svn的路徑即可。
sudo vim /var/lib/trac/waue/conf/trac.ini
-
/var/lib/trac/waue/conf/trac.ini
old new 165 165 permission_store = DefaultPermissionStore 166 repository_dir = /var/lib/ trac/waue166 repository_dir = /var/lib/svn/waue
WordCount.java
import java.io.IOException; import java.util.*; import org.apache.hadoop.fs.Path; import org.apache.hadoop.conf.*; import org.apache.hadoop.io.*; import org.apache.hadoop.mapred.*; import org.apache.hadoop.util.*; public class WordCount { public static class Map extends MapReduceBase implements Mapper<LongWritable, Text, Text, IntWritable> { private final static IntWritable one = new IntWritable(1); private Text word = new Text(); public void map(LongWritable key, Text value, OutputCollector<Text, IntWritable> output, Reporter reporter) throws IOException { String line = value.toString(); StringTokenizer tokenizer = new StringTokenizer(line); while (tokenizer.hasMoreTokens()) { word.set(tokenizer.nextToken()); output.collect(word, one); } } } public static class Reduce extends MapReduceBase implements Reducer<Text, IntWritable, Text, IntWritable> { public void reduce(Text key, Iterator<IntWritable> values, OutputCollector<Text, IntWritable> output, Reporter reporter) throws IOException { int sum = 0; while (values.hasNext()) { sum += values.next().get(); } output.collect(key, new IntWritable(sum)); } } public static void main(String[] args) throws Exception { JobConf conf = new JobConf(WordCount.class); conf.setJobName("wordcount"); conf.setOutputKeyClass(Text.class); conf.setOutputValueClass(IntWritable.class); conf.setMapperClass(Map.class); conf.setCombinerClass(Reduce.class); conf.setReducerClass(Reduce.class); conf.setInputFormat(TextInputFormat.class); conf.setOutputFormat(TextOutputFormat.class); FileInputFormat.setInputPaths(conf, new Path(args[0])); FileOutputFormat.setOutputPath(conf, new Path(args[1])); JobClient.runJob(conf); } }
製作 Executable JAR
- 產生出class檔
- 編寫MANIFEST.MF檔,格式如
Manifest-Version: 1.0 Created-By: ant 1.4 Main-Class: com.example.myAppMain Class-Path: mail.jar activation.jar
- jar -cvfm "ANY_NAME".jar MANIFEST.MF ["檔1".."檔n" | "路徑" ]
- java -jar "ANY_NAME".jar
製作可執行JAR的注意事項
- MANIFEST.MF 內的"Main-Class: "是唯一必要的欄位,其他可省略
- Main-Class: Main檔路徑 :後的空格要注意
- com.example.myAppMain 代表 執行檔myAppMain.class放在 "/com/example/"資料夾內
- jar -cvfm 的 fm 順序不可搞混。
- java -jar 的 - 不可省略,否則報錯
初階小試
0. 編程
指令:
vim test.java內容:
public class test{ public static void main(String[] args){ System.out.println("hello word"); } }
1. 編譯
指令:
javac test.java
2. 執行文件
指令:
vim MANIFEST.MF內容:
Main-Class: test
3. 打包
指令:
jar -cvfm test.jar MANIFEST.MF ./執行畫面如下:
新增 manifest 新增︰MANIFEST.MF (讀=17)(寫=19)(壓縮 -11%) 新增︰test.class (讀=514)(寫=330)(壓縮 35%)
4. 執行
指令:
java -jar test.jar執行畫面如下:
hello word
Eclipse 製成 JAR
0 run
程式需在Eclipse 上 run過,假設run完被紀錄的名稱為test
1 製作JAR 檔
在Package Explorer 找到程式碼的專案資料夾,右鍵點選export =>
打開Java類 -> Runnaable JAR file =>
Launch configuration -> "test" ;
Export destination->"隨便一個path" ->
Finish
2 執行
假設我們將匯出的jar放在桌面上,名稱為test.jar 則要執行它則是:
cd ~/Desktop java -jar test.jar
打包成exe檔工具
reference from 將Java程序作成exe文件的N種方法
| 名稱 | 介紹 | 說明 | 備註 |
| JET | 一個優秀的Java語言本地編譯器 | 用javac生成test.class 然後用 jc test.class+gui | 加個參數+gui,只是不顯示dos窗口,而不是完全的可以獨立運行的exe,還是需要jre的 |
| exe4j | 將Jar文件製作成exe文件,但需jre支持,也可將Jar文件放在外面。 | http://www.ej-technologies.com/products/exe4j/overview.html | 共享軟件 |
| jBuilder | JBuilder可以直接把工程製作成各系統的可執行文件,包括Windows系統。 | 商業軟件 | |
| nativeJ | 與exe4j功能類似。 | http://www.dobysoft.com/products/nativej/download.html | 共享軟件 |
| jshrink | 可將Jar文件打包進exe文件。同時具有混淆功能(這才是它的主要功能)。 | http://www.e-t.com/jshrink.html | 共享軟件 |
| installAnywhere | 打包工具,對Java打包最好用。可打包成各操作系統運行包。包括Windows系統。 | http://www.zerog.com/ | 商業軟件 |
| installShieldX | 與installAnywhere類似,但比installAnywhere功能強大。 | http://www.installshield.com | 商業軟件 |
| izPack | Java 安裝程序製作工具,能夠製作一些簡單的安裝程序 | 製作出來的安裝程序能在 Unix-like, MacOS X, Windows 等系統平台上運行。 | |
| sSmooth | 使用JSmooth將做好的JAR包裝成EXE。 | ||
| launch4j | Java應用程序的Windows本地可執行文件 (.exe) 封裝器 | 提供了本地彈出屏幕,應用程序圖標,JRE搜索或使用綁定的JRE,啟動失敗反饋,傳遞命令行參數,ant腳本。 | |
| vAInstall | 多平台的安裝程序。你要包裝起來的軟件可以是可執行的 java class, Windows .EXE, Linux 可執行檔,或者是 UNIX shell 檔案 | 可以選擇四種安裝的介面,graphic, xtra, text 或是 ansi | 只需要很少的空間,他不會使用任何大的暫存檔案,而且還可以很容易使用反安裝功能。 |
| toolshed | 一個既小又簡單的JAVA安裝製作工具。 | ||
| antInstaller | 通過XML文件定義UI,用Ant做後台。所以ANT所能做的事情antInstaller同樣也勝任。 | ||
| freeInstaller | freeInstaller能夠把JAVA程序打包成的應用程序 | 多種平台 | |
| setup2go | 是個很好用的安裝製作程序 | 有中文版,完全免費 |
詳細的圖文教學
Reference by Java Gossip: 製作 Executable JAR
撰寫Java程式到這邊,相信您一定會有所疑問的是,編出來的.class檔案越來越多,難道要將這一堆.class檔案直接給想要執行程式的人嗎?在Windows下的話,有沒有辦法按一下檔案,就可以執行程式呢?
當然,實際上要交付程式時,並不是給一堆.class檔案,而是會將編譯好的.class檔包裝為一個Java Archive File,也就是副檔名為.jar的檔案,在JDK的bin目錄下,附帶有一個jar工具程式,您可以直接執行jar程式,看看它的提示訊息:
直接執行jar工具程式,提示訊息中已清楚的說明如何使用jar程式,在這邊使用 文字編輯器製作 完成的文字編輯器為例,來示範如何將程式包裝為.jar的檔案,首先請建立一個jar目錄,並在其下建立bin與classes目錄,將您完成的文字編輯器程式放入classes中(包括套件的資料夾結構),待會將會產生的.jar則將放入bin中。
接著開啟文字模式,切換工作目錄至jar目錄下,然後鍵入以下的指令,表示將建立一個JNotePad.jar放到bin目錄中,來源是classes中的檔案,被放入的檔案將以/作為.jar檔案中的根目錄:
接著您的bin目錄中就會產生一個JNotePad.jar,要如何使用這個.jar檔案呢?.jar檔案中包括.class,基本上可以將.jar看作是一個特別的目錄,所以要使用.jar檔案中的.class檔案時,基本上也是指定Classpath,例如:
java -cp ./bin/JNotePad.jar onlyfun.caterpillar.JNotePad
接著您的文字編輯器就會啟動了,現在您不用將一堆.class檔案交付出去,只要交付這個JNotePad.jar就可以了。
然而,真的要指定Classpath這麼麻煩嗎?其實還有更方便的做法,製作一個Executable Jar檔案,指定讀取.jar檔案時要執行的Main-Class就可以了,這需要準備一個manifest.txt,當中寫下:
注意寫完Main-Class之後,要按下Enter鍵新增一行,在Windows下這個動作是必要的,否則會發生無法讀取Main-Class屬性的錯誤。假設manifest.txt放在jar目錄下,接著如下執行指令:
在.jar檔案製作出來後,您可以在執行java時指定-jar引數,以及您的.jar檔案,java程式會自動尋找Main-Class並執行,例如下達以下的指令:
java -jar bin/JNotePad.jar
接著您的文字編輯器就會啟動了,如果您的作業系統是Windows,由於安裝完JRE之後,會將.jar預設由javaw程式開啟,所以您可以直接在JNotePad.jar檔案上,使用滑鼠左鍵按兩下直接開啟程式來執行。
簡化設定叢集的登入驗證
動機
透過ssh免密碼登入主機來控制,已經是很普遍的一種方式來操控遠端Linux系統,不外乎將對方的public key加入到 authorized_keys,但是遇到網路環境中有大量的電腦需要互相驗證的時候,如在有10個節點的叢集環境中,因為要跑叢集程式,因此程式在每台電腦之間透過ssh運行都要暢行無阻。
以前的作法
1. 以第一節點為平台,ssh 登入到第二台,ssh-keygen產生密碼對,登出;再登入到第三台...依此類推。 2. 在第一節點收集其他電腦的public keys 3. 把十組public keys內容貼到authorized_keys 4. 把known_hosts檔與authorized_keys檔scp到其他電腦的.ssh資料夾中
詳細作法可參考: 兩小時叢集電腦
改進的作法
據小澤源所建議,只要在第一節點產生完密鑰對,然後scp -r .ssh到其他台電腦就可以了。以下列出詳細作法:
$ cd ~ $ ssh-keygen -t rsa -b 1024 -N "" -f ~/.ssh/id_rsa $ cp ~/.ssh/id_rsa.pub ~/.ssh/authorized_keys $ scp -r ~/.ssh/ "其他節點IP_or_HostName":~/
然後就可以快樂的使用此帳戶連到各台電腦都不用密碼了。
補充
免密碼的問題解決了,不過登入到沒有列在known_hosts的主機時,會有要求是否加入的詢問出現,因此要確定每台都有登入過。如果有一台沒登入過且是自動化程式的話,就會卡住,等你看到之後,回答yes,才會繼續,但為時已晚...。
因此可以修改ssh的編譯檔,使它預設不要詢問,而是自動加入到Known_hosts
編寫 /etc/ssh/ssh_config :
StrictHostKeyChecking no
ps : 注意原本是ask 改成是no,如果改成yes的話就會被Strict住,比ask更慘
其他設定
- 關於ssh_config的其他有趣設定參數,列如下
| Host | Restricts the following declarations (up to the next Host key-word) to be only for those hosts that match one of the patterns given after the keyword. |
| BatchMode | If set to yes, passphrase/password querying will be disabled. This option is useful in scripts and other batch jobs where no user is present to supply the password. The argument must be yes or no. The default is no. |
| PubkeyAuthentication | Specifies whether to try public key authentication. The argument to this keyword must be yes or no. The default is yes. This option applies to protocol version 2 only. |
- 每台ssh重新啟動
改寫一個shell如下,就可以自動把改好的ssh_config檔複製到每台節點並重新啟動ssh
#!/bin/bash for ((i=2;i<=7;i++)); do scp /etc/ssh/ssh_config "192.168.1.$i":/etc/ssh/ssh_config ssh "192.168.1.$i" /etc/init.d/ssh restart done





































