토렌트 사이트에는 광고도 많고, 페이지를 넘기면서 컨텐츠를 찾는게 여간 번거로운게 아니다. 


그래서 카테고리별로 목록과 토렌트의 웹 URL을 쭉 받아오는 파이썬 코드를 작성해 봤다. 


import lxml.html from lxml.cssselect import CSSSelector import requests import urllib.request baseUrl = 'https://itorrent.io' def getTorrentInfo(category): url = baseUrl + '/' + category +'/' for i in range(1, 200): targetUrl = url + str(i) r = requests.get(targetUrl) tree = lxml.html.fromstring(r.text) sel = CSSSelector('body > div > div.content > div.collection-container > ul > li > a') results = sel(tree) if (len(results) == 0): break for res in results: href = res.get('href') title = res.get('title') r2 = requests.get(baseUrl + href) tree2 = lxml.html.fromstring(r2.text) sel2 = CSSSelector('body > div > div.content > div.document-container > div:nth-child(3) > ul > li:nth-child(1) > a') results2 = sel2(tree2) torrentUrl = results2[0].get('href') filename = results2[0].get('data-encryption') print (title) print(torrentUrl) print ("") getTorrentInfo("documentary")

pip install lxml




[Hadoop] Map Reduce

빅 데이터 2017.01.30 19:19 Posted by mr.leedk

Hadoop을 설치해서 Map Reduce를 사용해보고 Hive를 설치해서 HiveQL을 사용해보자. 


Hadoop 설치 


먼저 AWS에 Centos6으로 인스턴스를 띄웠다. 

MAC에서 SSH로 접속을 위해 다음 작업을 해줘야 한다. 


chmod 600 mykey.pem

ssh -i mykey.pem centos@myip



일단 wget부터 설치 

yum install wget


그리고 자바 설치


wget --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u102-b14/jdk-8u102-linux-x64.rpm


yum localinstall jdk-8u102-linux-x64.rpm


java --version


하둡계정 생성


useradd hadoop

passwd hadoop


su hadoop


환경 변수 설정

 

vi ~/.bashrc


export JAVA_HOME=/usr/java/jdk1.8.0_102/
export JRE_HOME=/usr/java/jdk1.8.0_102/jre
export HADOOP_CLASSPATH=${JAVA_HOME}/lib/tools.jar
PATH=$PATH:$HOME/bin:$JAVA_HOME/bin

export PATH
source ~/.bash_profile

하둡 다운받기 


wget http://apache.mirror.cdnetworks.com/hadoop/common/hadoop-2.7.3/hadoop-2.7.3.tar.gz

tar xvzf hadoop-2.7.3.tar.gz

cd hadoop-2.7.3



Hadoop - Standalone


처음에 설치했으면 Standalone모드로 동작함. 

싱글 자바 프로세스로 동작함. 


Hadoop - Pseudo Distributed


한대에서 돌아가지만 각 하둡 데몬이 싱글 프로세스로 동작한다. 


vi etc/hadoop/core-site.xml

 <configuration>

    <property>
        <name>fs.defaultFS</name>
        <value>hdfs://localhost:9000</value>
    </property>
</configuration>


vi etc/hadoop/hdfs-site.xml

<configuration>
    <property>
        <name>dfs.replication</name>
        <value>1</value>
    </property>
</configuration>


ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa

cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys chmod 0600 ~/.ssh/authorized_keys


bin/hdfs namenode -format

sbin/start-dfs.sh


학습용 데이터 다운받기

cd  

wget http://files.grouplens.org/datasets/movielens/ml-20m.zip 

unzip ml-20m.zip


데이터를 hdfs에 올리기 

bin/hdfs dfs -put ~/ml-20m input


기본 example돌려보기

bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.3.jar grep input output '.*action.*'


hdfs의 output폴더를 로컬로 내려받기

bin/hdfs dfs -get output output cat output/*


이번에는 WordCount.java 를 수정해서 movieId의 개수를 세보기


vi WordCount.java


import java.io.IOException; import java.util.StringTokenizer; 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.Mapper; import org.apache.hadoop.mapreduce.Reducer; import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; public class WordCount { public static class TokenizerMapper 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(), ",");

String userId = itr.nextToken();

String movieId = itr.nextToken();

String rating = itr.nextToken();

String timestamp = itr.nextToken();

word.set(movieId); context.write(word, one); } } public static class IntSumReducer 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); } } public static void main(String[] args) throws Exception { Configuration conf = new Configuration(); Job job = Job.getInstance(conf, "word count"); job.setJarByClass(WordCount.class); job.setMapperClass(TokenizerMapper.class); job.setCombinerClass(IntSumReducer.class); job.setReducerClass(IntSumReducer.class); job.setOutputKeyClass(Text.class); job.setOutputValueClass(IntWritable.class); FileInputFormat.addInputPath(job, new Path(args[0])); FileOutputFormat.setOutputPath(job, new Path(args[1])); System.exit(job.waitForCompletion(true) ? 0 : 1); } }


컴파일

bin/hadoop com.sun.tools.javac.Main WordCount.java jar cf wc.jar WordCount*.class


Map Reduce실행

bin/hadoop jar wc.jar WordCount /user/hadoop/input/ratings.csv /user/hadoop/output3

결과 조회

bin/hadoop fs -cat /user/hadoop/output3/part-r-00000


MapReduce통한 결과와 일반 자바프로그램을 통해 구한 결과의 결과 비교 


자바 프로그램 쉽게 개발하기 위해 일단 maven설치


$ sudo wget http://repos.fedorapeople.org/repos/dchen/apache-maven/epel-apache-maven.repo -O /etc/yum.repos.d/epel-apache-maven.repo

$ sudo yum install apache-maven


vi ~/.bashrc


export M2_HOME=/usr/share/apache-maven

export M2=$M2_HOME/bin

export PATH=$PATH:$M2


mvn -version


간단히 메이븐 프로젝트 생성 

mvn -B archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes -DgroupId=com.mycompany.app -DartifactId=my-app


소스코드 작성

vi src/main/java/com/mycompany/app/App.java


package com.mycompany.app;


import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.FileReader;

import java.io.FileWriter;

import java.io.IOException;

import java.io.UnsupportedEncodingException;

import java.net.URLEncoder;

import java.util.List;

import java.util.StringTokenizer;

import java.util.HashMap;

import java.util.Map;


public class App

{

    public static void main( String[] args )

    {

        Map<String, Integer> map = new HashMap<String, Integer>();

        try {

                BufferedReader in = new BufferedReader(new FileReader("ratings.csv"));

                String line;

                while ((line = in.readLine()) != null) {

                        StringTokenizer itr = new StringTokenizer(line.toString(), ",");

                        String userId = itr.nextToken();

                        String movieId = itr.nextToken();

                        String rating = itr.nextToken();

                        String timestamp = itr.nextToken();

                        if (map.get(movieId) == null) {

                                map.put(movieId, 1);

                        }

                        else {

                                map.put(movieId, map.get(movieId) +1);

                        }

                }

                in.close();

        } catch (IOException e) {

                System.err.println(e);

                System.exit(1);

        }


        for (Map.Entry<String, Integer> itr : map.entrySet()) {

                System.out.println(itr.getKey() + ":" + itr.getValue());

        }

    }

}


[java 결과]

3640:96

3638:4680

3639:3846

3630:44

3631:33

3632:369

3633:2688

3634:895

3635:4179

3636:53

3637:158

3650:27

3651:26

3649:1397

1:49695


[hadoop 결과]

1       49695

10      29005

100     4115

1000    203

100003  3

100006  1

100008  6

100010  22

100013  5

100015  1

100017  10

100032  12

100034  17

100036  10


hadoop 결과의 특징은 key로 결과가 정렬되어 있다. 

key1에 대해 49695로 결과가 같음을 확인하였다. 


Hive란 무엇인가요? 


페이스북에서 개발 

HiveQL(SQL과 비슷) 제공. 

HiveQL이 내부적으로 맵리듀스 잡으로 변환되어 실행됨 

일일이 맵리듀스 자바 프로그래밍 하기 귀찮으니 있는 존재라고 볼 수 있다. 


Hive Download 
wget http://apache.mirror.cdnetworks.com/hive/hive-2.1.1/apache-hive-2.1.1-bin.tar.gz
tar xvzf apache-hive-2.1.1-bin.tar.gz

export HIVE_HOME=/home/hadoop/apache-hive-2.1.1-bin
export HADOOP_HOME=/home/hadoop/hadoop-2.7.3


HDFS에 hive를 위한 공간 만들기

$HADOOP_HOME/bin/hadoop fs -mkdir       /tmp

$HADOOP_HOME/bin/hadoop fs -mkdir       /user/hive/

$HADOOP_HOME/bin/hadoop fs -mkdir       /user/hive/warehouse

$HADOOP_HOME/bin/hadoop fs -chmod g+w   /tmp

$HADOOP_HOME/bin/hadoop fs -chmod g+w   /user/hive/warehouse


Hive설정 파일 셋팅 

mv conf/hive-env.sh.template conf/hive-env.sh


vi hive-env.sh

HADOOP_HOME=/home/hadoop/hadoop-2.7.3


cp hive-default.xml hive-site.xml 

vi hive-site.xml


<property>
    <name>hive.querylog.location</name>
    <value>/home/hadoop/apache-hive-2.1.1-bin/iotmp</value>
<description>Location of Hive run time structured log file</description> </property> <property> <name>hive.exec.local.scratchdir</name> <value>/home/hadoop/apache-hive-2.1.1-bin/iotmp</value>
<description>Local scratch space for Hive jobs</description> </property> <property> <name>hive.downloaded.resources.dir</name> <value>/home/hadoop/apache-hive-2.1.1-bin/iotmp</value>
<description>Temporary local directory for added resources in the remote file system.</description> </property>


$HIVE_HOME/bin/hive 실행 전에 반드시 

$HIVE_HOME/bin/schematool -initSchema -dbType derby


만약에 위 명령 실행하지 않았다면 

mv metastore_db metastore_db.tmp 하고 

$HIVE_HOME/bin/schematool -initSchema -dbType derby 한 후 실행해야 한다. 


hive cli실행했으면 테이블 정의 


CREATE TABLE ratings (userId String, movieId String, rating String, times String) 

ROW FORMAT DELIMITED 

FIELDS TERMINATED BY ',' 

LINES TERMINATED BY '\n' 

STORED AS TEXTFILE 

LOCATION '/home/hadoop/ml-20m/ratings.csv';


로컬 데이터로 테이블에 데이터 넣기 

LOAD DATA LOCAL INPATH '/home/hadoop/ml-20m/ratings.csv' OVERWRITE INTO TABLE ratings;


간단 쿼리 

select * from ratings2 limit 10;


집계 쿼리

select count(1) from ratings2 where movieId = 1;


결과

Number of reduce tasks determined at compile time: 1

Stage-Stage-1:  HDFS Read: 1335393910 HDFS Write: 3200666466 SUCCESS

Total MapReduce CPU Time Spent: 0 msec

OK

49695

Time taken: 15.036 seconds, Fetched: 1 row(s)


HBase

wget http://apache.mirror.cdnetworks.com/hbase/hbase-1.0.3/hbase-1.0.3-bin.tar.gz

tar xvzf hbase-1.0.3-bin.tar.gz


vi conf/hbase-site.xml


<configuration>
  <property>
    <name>hbase.rootdir</name>
    <value>file:///home/hadoop/hbase</value>
  </property>
  <property>
    <name>hbase.zookeeper.property.dataDir</name>
    <value>/home/hadoop/zookeeper</value>
  </property>
</configuration>


bin/start-hbase.sh


put 'test', 'row1', 'cf:a', 'value1'
put 'test', 'row2', 'cf:b', 'value2'
put 'test', 'row3', 'cf:c', 'value3'
scan 'test'
get 'test', 'row1'


./bin/hbase shell

./bin/stop-hbase.sh



Map Reduce에 대한 고찰 

Map은 텍스트의 한 줄씩 읽어서 <Key, Value>로 반환한다. 


그러면 Reduce에서는 <Key, List<Value>>를 인풋으로 받고 

그거에 대해 <Key, Value>로 반환한다. 


대략적으로 알았는데 구체적으로 몇 가지 궁금한게 있다. 


1. Block의 크기가 60MB라고 하자. 그리고 데이터의 크기는 240MB다. 

그러면, Map은 4개의 Task가 생기고 각각의 Task는 60MB 에 대해 책임을 지고 

한 줄씩 읽으면서 Map작업을 한다. 

Reduce는 이 Block단위로 이뤄질가?아니면 Global하게 이뤄질까? 

아마도 Global하게 이뤄지는 거 같고, 그 과정이 Shuffle 인 거 같다. 


2. Shutfle이란 무엇인가? 

Map에서 Reduce쪽으로 데이터 전달하는 과정이다. 

Map작업을 통한 Output이 키 별로 묶여서 Reduce작업의 Input으로 들어가는데 

그 과정에서 프레임워크가 해주는 일인 듯 싶다. 


3. 그렇다면 Map에서 Output으로 내놓는 Key, Value의 Key들이 로컬리티를 가진다면, 

즉, 하나의 Block안에 있다면, MR의 성능이 좋아질 수 있지 않을까 생각한다. 

정말 운이 좋다면, Map과 Shuffle이 하나의 Node안에서 이뤄질 수도 있지 않을까. 


Hadoop vs HBase 


hadoop은 HDFS와 Map Reduce Framework로 구성된다. 


HDFS는 파일을 분산, 복제하여 저장하는 파일 시스템이고, 그 위에서 device&conquere방식으로 

분산 병렬 처리할 수 있는 처리 프로세스가 Map Reduce이다. 


Hadoop에서는 무언가 작은 거 하나라도 검색하려면 전체 데이터 셋을 뒤져야만 한다...


그래서 HBase가 나왔고, key/value방식으로 빠른 시간에 검색이 가능하다. 


컬럼 기반, 


어떻게 그게 가능했을까? HBase가 HDFS를 사용한다는데 말이다. 





Hadoop sends identical keys to the same reducer

 






[sublime] my regex plugin

프로그래밍 2017.01.14 11:55 Posted by mr.leedk

정규식 치환은 문서 작업 중 매우 유용하게 사용될 수 있는 기능이다. 

일반적으로 ctrl + f 해서 정규식을 집어서 replace 하면 되지만, 

자주 사용하는 정규식 치환은 sublime text의 plugin으로 만들어놓으면 더 편리할 것이다. 

특히, 한번의 작업을 끝내기 어려운 경우에는 여러 단계의 변환 작업을 프로그래밍 해놓으면 

한방에 바꿀 수 있어 매우 효율적이다. 




일단 Tools > Developer > New Plugin을 통해 기본 뼈대를 만든다. 



일단 class 의 이름을 MyRegexCommand로 바꿨다. 

mac에서 control + ` 를 누르면 콘솔이 뜬다. 

여기서 view.run_command('my_regex') 해보면 

현재 에디터 창에 Hello World가 작성되는 것을 확인할 수 있다. 


내가 만든 정규식 플러그인 코드는 다음과 같다. 


import sublime
import sublime_plugin
import re


class MyRegexCommand(sublime_plugin.TextCommand):
	def run(self, edit):
		sels = self.view.sel()
		for sel in sels:
			line = self.view.substr(self.view.line(sel))
			# newline = line.replace('print', 'print2')
			newline = re.sub(r"print", "print3", line).rstrip()
			self.view.erase(edit, sel)
			self.view.insert(edit, sel.a-len(line), newline)
			


[간단 코드 설명]

sublime text 에디터에서 선택한 region이 sels에 있음. (서브라임은 복수 region 선택이 가능)

sels에 대해 for문 돌면서 각 region의 문자열을 line에 저장. 


line 문자열에 대해 정규식 변환 수행. 

python의 re 모듈 사용. 

re.sub(정규식 패턴, 변환할 문자열, 대상 문자열) 


그리고, rstrip() 은 문자열 끝에 있는 공백을 trim해준다. 


선택한 region삭제하고, (self.view.erase)

정규식 변환된 문자열을 삽입. (self.view.insert)

'프로그래밍' 카테고리의 다른 글

[sublime] my regex plugin  (0) 2017.01.14
Mac 단축키  (0) 2016.12.31
[Java] 영어 형태소 분석 사용 예  (0) 2016.12.25
youtube-dl 소스 코드 분석  (0) 2016.12.24
AWS - Centos 6.5 nodejs, phantomjs 환경 구축  (0) 2016.12.10
[Javascript] 정규식 사용 예  (0) 2016.11.06