2020년 11월 25일 수요일

Hive [7] - Hive to Phoenix Table


[ 사전셋팅 (Prerequisites) ]

phoenix-version-hive.jar 파일을 찾고, 

해당 하이브 설정파일에 value를 추가하여 하이브 맵리듀스 잡이 jar파일 사용하게 한다.

1) hive-env.sh : HIVE_AUX_JARS_PATH=<path to jar>

2) hive-site.xml

<property>

    <name>hive.aux.jars.path</name>

    <value>file://<path></value>

</property>




[ 테이블 생성 ]

jar파일에 있는 storage Handler는 internal과 external 하이브테이블 생성을 지원한다.


1) Create Internal Table

Hive에서 테이블생성시 Phoenix에도 자동으로 테이블 생성되며, Hive나 Hue에서 데이터 조회와 같은 쿼리가 가능하다.

Internal Phoenix테이블은 Hive테이블 lifecycle을 따른다. 즉 Hive테이블에서 데이터 또는 테이블이 삭제되면 Phoenix테이블 또한 동일하게 영향을 받는다.

create table phoenix_table (
	  s1 string,
	  i1 int,
	  f1 float,
	  d1 double
	)
	STORED BY 'org.apache.phoenix.hive.PhoenixStorageHandler'
	TBLPROPERTIES (
	  "phoenix.table.name" = "phoenix_table",
	  "phoenix.zookeeper.quorum" = "localhost",
	  "phoenix.zookeeper.znode.parent" = "/hbase",
	  "phoenix.zookeeper.client.port" = "2181",
	  "phoenix.rowkeys" = "s1, i1",
	  "phoenix.column.mapping" = "s1:s1, i1:i1, f1:f1, d1:d1",
	  "phoenix.table.options" = "SALT_BUCKETS=10, DATA_BLOCK_ENCODING='DIFF'"
	);



2) Create External Table

Hive에서 테이블생성시 Phoenix에 맵핑되는 테이블이 없으면 생성이 불가능하다. 테이블과 데이터를 따로 metadata로 매니징하기에 Hive나 Hue에서 데이터 조회 등의 쿼리를 실행 할 수 없다. 

External Phoenix테이블은 Hive테이블에 큰 영향을 받지않는다. Hive테이블에서 데이터 또는 테이블이 삭제되어도 Phoenix테이블 또한 동일하게 영향을 받는다.

create external table ext_table (
  i1 int,
  s1 string,
  f1 float,
  d1 decimal
)
STORED BY 'org.apache.phoenix.hive.PhoenixStorageHandler'
TBLPROPERTIES (
  "phoenix.table.name" = "ext_table",
  "phoenix.zookeeper.quorum" = "localhost",
  "phoenix.zookeeper.znode.parent" = "/hbase",
  "phoenix.zookeeper.client.port" = "2181",
  "phoenix.rowkeys" = "i1",
  "phoenix.column.mapping" = "i1:i1, s1:s1, f1:f1, d1:d1"
);



[ 생성 Properties ]

  1. phoenix.table.name
    • Specifies the Phoenix table name
    • Default: the same as the Hive table
  2. phoenix.zookeeper.quorum
    • Specifies the ZooKeeper quorum for HBase
    • Default: localhost
  3. phoenix.zookeeper.znode.parent
    • Specifies the ZooKeeper parent node for HBase
    • Default: /hbase
  4. phoenix.zookeeper.client.port
    • Specifies the ZooKeeper port
    • Default: 2181
  5. phoenix.rowkeys
    • The list of columns to be the primary key in a Phoenix table
    • Required
  6. phoenix.column.mapping
    • Mappings between column names for Hive and Phoenix. See Limitations for details.



[ Meta데이터위치 ]

Zookeeper znode를 확인하면 /hbase/archive/data 에 hive와 연동된 phoenix메타데이터가 담긴다. 

/hbase/data에 테이블이 정의되어 있더라도 해당 파일을 지우면 phoenix에서 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable 에러를 띄우며 트래킹할 수 없다는 메세지를 보낸다.




참조 : https://phoenix.apache.org/hive_storage_handler.html



 

[AWS] Php를 이용한 S3 이미지 업로드와 CloudFront에 추가

[ 순서 ]

Preparation : php설치, AWS CloudFront 사용 중

  • S3 사용을 위해 AWS-SDK-PHP 설치

  • 보안자격증명 key, secret 얻기

  • S3이미지 업로드 Php코드작성

  • S3버킷만들기

  • CloudFront에 S3 연동




[ AWS-SDK-PHP 설치 ]

1 2 3 4 5 6 7 8 9 10 11 php composer 설치 #php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" #php -r "if (hash_file('sha384', 'composer-setup.php') === '756890a4488ce9024fc62c56153228907f1545c228516cbf63f885e036d37e9a59d27d63f46af1d4d07ee0f76181c7d3') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" #php composer-setup.php #php -r "unlink('composer-setup.php');" composer 전역설정 # sudo cp composer.phar /usr/bin/composer aws-sdk-php설치 #sudo composer require aws/aws-sdk-php

 


[ 보안자격증명 key, secret 얻기 ]

우측상단 계정클릭 → 내보안자격증명 → 액세스키 생성하여 key, secret 포함된 CSV파일 다운












[ S3버킷 설정 ]

1. AWS S3탭에 들어가 버킷생성

2.버킷을 퍼블릭으로 설정

3.해당버킷대쉬보드 → 권한 → 버킷정책

{
"Version": "2020-12-04",
"Statement": [
{
"Sid": "AddPerm",
"Effect": "Allow",
"Principal": "",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::yourBucketName/"
}
]
}


[ S3이미지 업로드 PHP code ]

Post로 File업로드시 필요한 파람터 값을 받는다. S3에 대한 리전, key, secret, 버킷이름 등의 정보를 입력하고, 앞서 다운받았던 aws-sdk-php API를 이용해 업로드 코드를 작성한다.

예제 )

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #Php to aws S3 require '/PATHtoAWSSDK/aws-sdk/vendor/autoload.php'; use Aws\S3\S3Client; use Aws\Exception\AwsException; use Aws\Credentials\CredentialProvider; #Bucket 연결 객체 $s3Client = new S3Client([ 'region' => 'ap-northeast-1', 'version' => 'latest', # 자격증명 'credentials' => [ 'key' => 'your_key', 'secret' => 'your_secret', ], ]); #File Upload to S3 $fp = fopen($upload_file, r); $result = $s3Client->putObject([ 'Bucket'=>'upload-image-file', 'Key' => $_FILES['file1']['name'], 'Body' => $fp ]); fclose($fp);

참고 : https://docs.aws.amazon.com/ko_kr/sdk-for-php/v3/developer-guide/getting-started_basic-usage.html



[ CloudFront에 S3추가 ]

AWS CloudFront → Create Distribution → Web섹션 Get Started → Origin Domain Name에 만든 S3 Name으로 입력한다.














나머지 설정은 읽어보면서 입력하고 Distribution Settings에 Price Class입력란을 보면 Class 마다 제공되는 Location과 가격이 다르다.














예를 들어 내 서비스가 아프리카국가의 유저들에게는 지원을 하지 않는다면 요금계층200을 선택해 요금을 더 지불하지 않도록 한다.


또한 모든 Location에 CloudFront를 지원하지 않기에 아래 그림을 참조하여 가장 가까운 Edge Location을 찾아 시스템라인을 구성해야 할 것이다.

예를 들어 중국하얼빈 유저들에게 내 웹/앱 서비스를 할 경우 CloudFront Location은 거리상으로 베이징보다 서울이 가깝다고 해보자. 그럼 중국이 포함된 Price Class를 사용하는게 아닌 한국이 포함된 Class를 써야 가장 최적의 네트워크 속도를 가질 것이다.



마지막으로 SSL Certificate된 사용할 도메인을 입력한다.



[ CloudFront Behaviors ]

cloudfront → 변경할 Distributions → Behaviors 탭 → Create Behavior 버튼 → 생성후 저장 Pattern은 * 로 작성




CloudFront 참조 : https://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/Introduction.html

https://www.slideshare.net/lacryma1/53-aws-summit-seoul-2015

https://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/distribution-web-values-specify.html#DownloadDistValuesPathPattern



RedHat7&Centos7 APM(apache/Php/mysql) 설치

[ 버전정보 ]

  • Httpd 2.4
  • Php 7.3
  • mariaDB 5.5


[ EC2에 APM설치 ]

  • httpd2.4 설치

#sudo yum install httpd

#httpd -v
Server version: Apache/2.4.6 (Red Hat Enterprise Linux)

 

  • Apache httpd vhost 설정

#sudo vi /etc/httpd/conf/httpd.conf

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 Listen 8080 (추가) ..... (VirtualHost 추가) <VirtualHost *:80> ServerName servername:80 ServerAdmin root@example.com DocumentRoot "/var/www/html/server1" CustomLog "logs/access_log" combined ErrorLog "logs/error_log" <Directory "/var/www/html/server1"> Options Indexes FollowSymLinks AllowOverride None Require all granted </Directory> </VirtualHost> <VirtualHost *:8080> ServerName servername:8080 ServerAdmin root@example.com DocumentRoot "/var/www/html/server2" CustomLog "logs/access_log" combined ErrorLog "logs/error_log" <Directory "/var/www/html/server2"> Options Indexes FollowSymLinks AllowOverride None Require all granted </Directory> </VirtualHost> .....

#sudo systemctl restart httpd

 

  • php73 설치

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 remi repository를 yum 에 추가 한다. # wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm # rpm -Uvh epel-release-latest-7.noarch.rpm # wget http://rpms.remirepo.net/enterprise/remi-release-7.rpm # rpm -Uvh remi-release-7.rpm # yum install -y yum-utils # yum-config-manager --enable remi-php73 기존의 설치된 PHP 패키지를 확인하여 잘못된 패키지가 삭제되지 않도록 한다. # yum list installed | cut -d " " -f 1 | grep php 기존 설치된 PHP를 제거. (php5) #yum remove -y `yum list installed | cut -d " " -f 1 | grep php` php 패키지 설치. php-common 외의 패키지는 자신의 상황에 맞게 조정해서 설치한다. # yum install -y php-common php-fpm php-cli \ php-process \ php-opcache php-pecl-apcu \ php-mysqlnd php-pdo \ php-gd \ php-mbstring php-xml \ php-pecl-zip \ php-bcmath #php -v PHP 7.3.34

 

  • mariadb 설치

#yum install mariadb mariadb-server 

#mysql --version
mysql Ver 15.1 Distrib 5.5.68-MariaDB, for Linux (x86_64) using readline 5.1

 

  • APM설정파일 경로

/etc/php.ini

/var/lib/php/

/etc/httpd/conf.d/php.conf

/etc/httpd/conf/httpd.conf

 

  • 명령어

-실행

sudo systemctl start httpd

sudo systemctl start mariadb

-확인

sudo systemctl status httpd

sudo systemctl status mariadb



[Algorithm] 힙 우선순위큐 [Heap Priority Queue] (더 맵게)


문제 ]

매운 것을 좋아하는 Leo는 모든 음식의 스코빌 지수를 K 이상으로 만들고 싶습니다. 모든 음식의 스코빌 지수를 K 이상으로 만들기 위해 Leo는 스코빌 지수가 가장 낮은 두 개의 음식을 아래와 같이 특별한 방법으로 섞어 새로운 음식을 만듭니다.

섞은 음식의 스코빌 지수 =  가장 맵지 않은 음식의 스코빌 지수 + (두 번째로 맵지 않은 음식의 스코빌 지수 * 2)

Leo가 가진 음식의 스코빌 지수를 담은 배열 scoville과 원하는 스코빌 지수 K가 주어질 때, 모든 음식의 스코빌 지수를 K 이상으로 만들기 위해 섞어야 하는 최소 횟수를 return 하도록 solution 함수를 작성해주세요.
제한 사항

  • scoville의 길이는 2 이상 1,000,000 이하입니다.
  • K는 0 이상 1,000,000,000 이하입니다.
  • scoville의 원소는 각각 0 이상 1,000,000 이하입니다.
  • 모든 음식의 스코빌 지수를 K 이상으로 만들 수 없는 경우에는 -1을 return 합니다.


입력

scovile = [1,2,3,9,10,12]
K = 7
출력
return 2

입출력 예 설명
  1. 스코빌 지수가 1인 음식과 2인 음식을 섞으면 음식의 스코빌 지수가 아래와 같이 됩니다. 새로운 음식의 스코빌 지수 = 1 + (2 * 2) = 5
    가진 음식의 스코빌 지수 = [5, 3, 9, 10, 12]

  2. 스코빌 지수가 3인 음식과 5인 음식을 섞으면 음식의 스코빌 지수가 아래와 같이 됩니다. 새로운 음식의 스코빌 지수 = 3 + (5 * 2) = 13
    가진 음식의 스코빌 지수 = [13, 9, 10, 12]

모든 음식의 스코빌 지수가 7 이상이 되었고 이때 섞은 횟수는 2회입니다. Leo는 모든 음식의 스코빌 지수가 K 이상이 될 때까지 반복하여 섞습니다.



제출 1 ] 

class Solution {
    public int solution(int[] scoville, int K) {
        int answer = 0;
        int result = 0;
        if(K==0) return 0;
        Arrays.sort(scoville);
        for(int i=0;i<scoville.length;i++){
            System.out.println(Arrays.toString(scoville));
            if(scoville[i]==0) return -1;
            if(scoville[i]<K){
                result = scoville[i]+(scoville[i+1]*2);
                if(result > scoville[i+2]) {
                    scoville[i+1]=scoville[i+2];
                    scoville[i+2]=result;    
                }
                answer++;
            } else {
                break;
            }
        }
        System.out.println(answer);
        return answer;
    }
}
몇 몇 테스트에서 타임아웃과 효율성테스트 실패.
결국 힙을 써야될 것같은데 자바의 Priority queue자료형쓰라는 문제였다.


[ Priority queue ]
큐의 구조를 가지면서 우선순위가 높은 엘리먼트가 먼저 poll되는 자료구조이다. 우선순위는 최대힙(내림차순)과 최소힙(오름차순)이 있으며 힙영역 메모리를 사용한다.












이진트리로 되어있으면 최대힙이면 root노드에 가장 큰 값, 
최소힙이면 root노드에 가장 작은 값이 들어간다.

기본적으로 import java.util.PriorityQueue; 를 임포트하고
PriorityQueue<제네릭> pq = new PriorityQueue<>(); 변수를 선언하여 사용한다. 

큐에 값을 추가하는 함수는
  • pq.add() / pq.offer()
큐에 값을 삭제하는 함수
  • pq.poll() // 첫번째 값(루트노드)을 반환하고 제거 비어있다면 null
  • pq.remove() // 첫번째 값 제거
  • pq.clear() // 우선순위 큐 초기화
출력 함수
  • pq.peek() // 우선순위 큐 첫번째 값 출력
  • pq.size() // number of elements present in the PriorityQueue


제출 2 ] 
import java.util.PriorityQueue;
class Solution {
public int solution(int[] scoville, int K) {
            PriorityQueue<Integer> pq = new PriorityQueue<>();
    int answer = 0;
        
            for (int i=0; i < scoville.length; i++){
                pq.add(scoville[i]);
            }

            while(pq.peek() < K){
                if (pq.size() < 2) return -1;
                int a = pq.poll();
        int b = pq.poll();
        pq.add(a + 2 * b);
        answer++;
            }
        return answer;
}
}



우선순위 큐 참조 : 
https://coding-factory.tistory.com/603