2020년 11월 22일 일요일

[Algorithm] 스택&큐 ( 주식가격 )


문제 ]

초 단위로 기록된 주식가격이 담긴 배열 prices가 매개변수로 주어질 때,

가격이 떨어지지 않은 기간은 몇 초인지를 return하시오.


- 입출력 예

prices : [ 1, 2, 3, 2, 3]

return : [ 4, 3, 1, 1, 0]




제출 ]

선택정렬 비스무리한 느낌이나서 이중 for문으로 해결하면 되지 않을까?

하는 생각으로 stack을 사용하지 않고 제출


class Solution {

    public int[] solution(int[] prices) {

        int len = prices.length;

        int[] answer = new int[len];


        for(int i=0; i<len; i++){

            for(int j=i+1; j<len; j++){

                answer[i]++;

                if (prices[i] > prices[j]){

                    break;

                }

            }

        }

        return answer;

    }

}



제출 2 ]

Stack을 이용한 다른분의 풀이


import java.util.Stack;

class Solution {

    public int[] solution(int[] prices) {

        Stack<Integer> beginIdxs = new Stack<>();

        int i=0;

        int[] terms = new int[prices.length];


        beginIdxs.push(i);

        for (i=1; i<prices.length; i++) {

            while (!beginIdxs.empty() && prices[i] < prices[beginIdxs.peek()]) {

                int beginIdx = beginIdxs.pop();

                terms[beginIdx] = i - beginIdx;

            }

            beginIdxs.push(i);

        }

        while (!beginIdxs.empty()) {

            int beginIdx = beginIdxs.pop();

            terms[beginIdx] = i - beginIdx - 1;

        }

        return terms;

    }

}


- Int형 제네릭 스택 선언, 스택함수로는

stack.push(obj) : 가장 탑에 데이터 추가

stack.pop() : 최근에 추가된 데이터 삭제

stack.peek() : 최근에 추가된 데이터 조회

stack.empty() : stack값이 비었는지 확인, 비면 True 아니면 False


 

2020년 11월 16일 월요일

Apache Kafka - 재시작시 meta.propertie 에러


에러메세지 ]

[2020-11-16 06:12:51,050] ERROR Fatal error during KafkaServer startup. Prepare to shutdown (kafka.server.KafkaServer)

kafka.common.InconsistentClusterIdException: The Cluster ID lTeGi4hnRaKFOHhVMQnfEg doesn't match stored clusterId Some(eaVbu41vRfSi-XzD7DxMog) in meta.properties. The broker is trying to join the wrong cluster. Configured zookeeper.connect may be wrong.

        at kafka.server.KafkaServer.startup(KafkaServer.scala:223)

        at kafka.server.KafkaServerStartable.startup(KafkaServerStartable.scala:44)

        at kafka.Kafka$.main(Kafka.scala:82)

        at kafka.Kafka.main(Kafka.scala)



원인 ]

해당파일을 찾아 열어보면

cat /mnt/data/kafka-logs/meta.propertie

    cluster.id=lTeGi4hnOodaKFOHhVMQnfEg

    version=0

    broker.id=1

와 같이 되어있는데,

정상적이지 않은 종료, 재시작으로 broker.id에 해당하는 cluster.id가 맞지 않아 생긴다.



해결 ]

해당 파일을 지우고 카프카 재시작한다.

sudo rm /mnt/data/kafka-logs/meta.propertie



[Algorithm] 해시맵 ( 완주하지 못한 선수 )

문제 ]

수많은 마라톤 선수들이 마라톤에 참여하였습니다. 단 한 명의 선수를 제외하고는 모든 선수가 마라톤을 완주하였습니다.

마라톤에 참여한 선수들의 이름이 담긴 배열 participant와 완주한 선수들의 이름이 담긴 배열 completion이 주어질 때, 완주하지 못한 선수의 이름을 return 하도록 solution 함수를 작성해주세요.


제한사항

  • 마라톤 경기에 참여한 선수의 수는 1명 이상 100,000명 이하입니다.
  • completion의 길이는 participant의 길이보다 1 작습니다.
  • 참가자의 이름은 1개 이상 20개 이하의 알파벳 소문자로 이루어져 있습니다.
  • 참가자 중에는 동명이인이 있을 수 있습니다.



제출 ]

import java.util.Arrays;

class Solution {

    public String solution(String[] participant, String[] completion) {

        String answer = "";

        Arrays.sort(participant);

        Arrays.sort(completion);

        int i;

        for(i=0; i < completion.length; i++){

            if(!participant[i].equals(completion[i])){

                return participant[i];

            }

        }

        return participant[i];

    }

}



풀이 ]











사진출처 :https://medium.com/@nsh235482


Arrays.sort함수를 이용하여 두배열을 정렬하면 두가지의 경우가 생긴다.

1. 위 그림처럼 맨뒤에 완주하지 못한 사람이 남는 경우

2. 배열 처음~중간에 두 배열 값이 일치하지 않는 경우


(2)의 경우 for문을 통해 처리했고 (1)의 경우에는 for문이 끝난 후 i 값이 맨 마지막 배열의 인자를 가리키게되므로 마지막 return코드로 처리한다.


처음에는 int i를 for문에 (i=0; i < completion.length; i++) 처럼 선언하고 

마지막 리턴문을 retrun participant[participant.length -1] 로 작성했는데 위의 제출코드처럼 수정한 것이 더 깔끔해보인다.

문제를 처음 보고 해시맵문제인데 해시를 안써도 되겠단 생각이 들었지만, 문제 제출 후 다른 분들이 해시를 이용한 코드를 참고할 수 밖에 없었다.



제출 2 ]

import java.util.HashMap;

class Solution{

    public String solution(String[] participant, String[] completion) {

        String answer = "";

        HashMap<String, Integer> hm = new HashMap<>();

        for (String player : participant) hm.put(player, hm.getOrDefault(player, 0) +1);

        for (String player : completion) hm.put(player, hm.get(player) -1);

        

        for (String key : hm.keySet(0) {

           if (hm.get(key) != 0){

               answer = key;

            }

        }

        return answer;

    }

}



풀이 2 ]

participant배열 값들은 모두 1의 값을 가지는 맵을 정의한다.

ex ) 존 : 1, 잭: 1, 에밀리 : 1......

동명이인일 때는 +1을 한번더 하여 "존 : 2" 가 되도록한다. 


그 뒤 completion배열과 map의 키값을 비교하여 각 value -1을 한다.

ex ) 존 : 1, 잭 0, 에밀리 : 0 ....

결국 1이 남는 key값이 완주하지 못한 선수이다.


* for ( key value : map.keySet() ) : map의 iterator기능을 하는 for 문

* map.getOrDefault ( key, default value) : 찾는 키가 존재한다면 그 키값을 반환하고 없다면 기본값을 반환한다.

* HashMap 함수

  • put()
  • putAll()
  • get()
  • remove()
  • clear()
  • isEmpty()
  • keySet()
  • values()
  • containsKey()
  • containsValue()
  • replace()

 



2020년 11월 12일 목요일

Apache Nifi [2] - Queued 설정


Queued 우측클릭->구성설정 버튼을 클릭하면 아래와 같이
설정할 수 있는 창이나온다.





FlowFile Expiration

FlowFile Expiration은 특정기간에 쌓인 데이터들 중 처리할 수 없는 데이터를 자동으로 제거할 수 있는 개념이다. 예를 들어 큐의 데이터 볼륨이 초과할 것으로 예상됬을 때, 유통기한을 우선 순위자와 함께 사용하여 우선 순위가 가장 높은 데이터를 먼저 처리한 후 일정 기간(예: 1시간) 내에 처리할 수 없는 것은 모두 삭제할 수 있다. 

만료 기간은 데이터가 NiFi 인스턴스에 들어간 시간을 기준으로 한다. 즉, 특정 연결의 FlowFile Expiration가 '1시간'으로 설정되어 있고 NiFi 인스턴스에 1시간 동안 있었던 파일이 해당 연결에 도달하면 만료된다. 

기본값 0초는 데이터가 절대 만료되지 않음을 나타낸다. '0초' 이외의 파일 만료를 설정하면 연결 라벨에 작은 시계 아이콘이 나타나기 때문에 흐름을 한눈에 볼 수 있다.







Back pressure

NiFi는 Back Pressure를 위한 두 가지 구성 요소를 제공한다. 임계값은 원본 데이터소스가 대기열에 존재할 수 있는 데이터 양을 나타낸다. 이를 통해 시스템이 데이터 오버런을 방지할 수 있다. 

제공되는 첫 번째 옵션은 "Back pressure object threshold"이다. 이것은 Back pressure를 적용하기 전에 대기열에 포함될 수 있는 FlowFiles 수를 나타낸다. 

두 번째 구성 옵션은 "Back pressure 데이터 크기 임계값"이다. 이것은 Back pressure를 적용하기 전에 대기열에 넣어야 하는 최대 데이터 양(크기)을 지정한다. (바이트의 경우 B, 킬로바이트의 경우 KB, 메가바이트의 경우 MB, 기가바이트의 경우 GB 또는 테라바이트의 경우 TB)

기본적으로 새로 추가된 각 연결dml  기본 Back pressure설정 값은 임계값 10,000개와 데이터 크기 임계값 1GB이다. 

활성화되면 연결 라벨에 작은 진행 표시줄이 나타나므로 캔버스의 흐름을 볼 때 이를 한눈에 볼 수 있다. 대기열 백분율에 따라 진행률 표시줄의 색 변경: 녹색(0~60%), 황색(61~85%), 적색(86~100%) 등이었다.




Load Balancing (부하 분산 전략)

NiFi는 데이터의 흐름을 클러스터 노드 전체에 분산시키기 위해 다음과 같은 로드 밸런싱 전략을 제공한다.
























Do not load balance : 클러스터의 노드 간에 FlowFiles를 로드 밸런싱하지않는다(기본값).

Partition by attribute : 사용자 지정 FlowFile 특성의 값에 따라 데이터를 보낼 노드를 결정한다. 속성 값이 동일한 모든 FlowFiles는 클러스터의 동일한 노드로 전송된다. 대상 노드가 클러스터에서 분리되거나 통신할 수 없는 경우, 노드가 다시 사용 가능해질 때까지 기다린다. 

Round robin : FlowFiles는 라운드 로빈 방식으로 클러스터의 노드에 배포된다. 노드가 클러스터에서 분리되거나 노드와 통신할 수 없는 경우, 해당 노드에 대기 중인 데이터는 자동으로 다른 노드로 재분산된다. 노드가 클러스터의 다른 노드처럼 데이터를 빠르게 수신할 수 없는 경우, 클러스터 전체의 데이터 배포 처리량을 극대화하기 위해 노드를 하나 이상 반복하여 건너뛸 수도 있다.

Single node : 모든 FlowFiles는 클러스터의 단일 노드로 전송된다. 어떤 노드로 전송되는지는 구성할 수 없다. 노드가 클러스터에서 분리되거나 노드와 통신할 수 없는 경우, 해당 노드에 대해 대기 중인 데이터는 노드를 다시 사용할 수 있을 때까지 대기열에 남아 있게 된다.



연결에 대해 로드 밸런싱 전략을 실행한 경우 연결에 로드 밸런싱 표시기(Load Balance Icon)가 나타난다.












Available Prioritizers (우선 순위 지정)

첫번째 이미지 탭의 오른쪽은 더 높은 우선순위 데이터가 먼저 처리되도록 대기열에서 데이터의 우선순위를 지정할 수 있는 기능을 제공한다. 우선순위 지정자를 위에서 아래로 끌 수 있다. 






참고 : https://nifi.apache.org/docs/nifi-docs/html/user-guide.html

Apache Zeppelin [5] - 인증 및 접근권한 설정


제플린의 인증은 shiro.ini파일로 설정한다.


sudo cp /usr/local/zeppelin/conf/shiro.ini.template /usr/local/zeppelin/conf/shiro.ini

sudo vi /usr/local/zeppelin/conf/shiro.ini

sudo /usr/local/zeppelin/bin/zeppelin-daemon.sh restart


재시작후 웹페이지에서 제플린메인을 접속하면,

기존 anonymous계정으로 로그인과 인터프리터, 설정등 페이지에 접근이 불가능하다.



[ Shiro.ini Config ]

설정파일은 main, users, roles, urls와 같이 4파트로 나뉘는데 

각 파트별 설정내용은 다음과 같다.


[main] :Realm과 같은 Security Managerd의 object와 properties가 정의

[users] : 사용자 계정과 관련된 properties가 정의

[roles] : 계정의 roles와 관련된 설정값

[urls] : URL 기반 보안에 사용


* Realm

사용자, 역할 및 권한과 같은 애플리케이션별 보안 데이터에 액세스할 수 있는 구성 요소다. Realmssms 애플리케이션별 데이터를 Shiro가 이해한 형식으로 변환하여 데이터 소스가 얼마나 많든, 애플리케이션별로 어떻게 존재하든 Shiro가 이해하기 쉬운 단일 프로그래밍 API를 제공할 수 있도록 한다.

Realms는 관계형 데이터베이스, LDAP 디렉토리, 파일 시스템 또는 기타 유사한 리소스와 같은 데이터 소스와 1 대 1의 상관관계를 가진다. Realms의 인터페이스의 구현은 데이터 소스별 API를 사용하여 JDBC, 파일 IO, 최대 절전 모드 또는 JPA와 같은 권한 부여 데이터(역할, 권한 등)의 Data Access API를 제공한다.

참조 : http://shiro.apache.org/realm.html




1. MAIN

Active Directory 

activeDirectoryRealm = org.apache.zeppelin.realm.ActiveDirectoryGroupRealm
activeDirectoryRealm.systemUsername = userNameA
activeDirectoryRealm.systemPassword = passwordA
activeDirectoryRealm.hadoopSecurityCredentialPath = jceks://zeppelin/conf/zeppelin.jceks
activeDirectoryRealm.searchBase = CN=Users,DC=SOME_GROUP,DC=COMPANY,DC=COM
activeDirectoryRealm.url = ldap://ldap.test.com:389
activeDirectoryRealm.groupRolesMap = "CN=aGroupName,DC=COMPANY,DC=COM":"group1"
activeDirectoryRealm.authorizationCachingEnabled = false
activeDirectoryRealm.principalSuffix = @corp.company.net


LDAP

LDAP Realms를 구성하기 위해 가장 사용하기 쉬운 것은 LdapGroupRealm이다.

LDAP 그룹을 사용자에 매핑하고 사용자 그룹에 대한 권한 부여를 위한Realms 설정은 다음과 같다.

ldapRealm = org.apache.zeppelin.realm.LdapGroupRealm
# search base for ldap groups (only relevant for LdapGroupRealm):
ldapRealm.contextFactory.environment[ldap.searchBase] = dc=COMPANY,dc=COM
ldapRealm.contextFactory.url = ldap://ldap.test.com:389
ldapRealm.userDnTemplate = uid={0},ou=Users,dc=COMPANY,dc=COM
ldapRealm.contextFactory.authenticationMechanism = simple


PAM

PAM 인증 지원을 통해 제플린이 실행 중인 호스트에서 기존 인증 모듈을 재사용할 수 있다. 일반적인 시스템 모듈에서는 /etc/pam.d/에 따라 sshd, passwd 등의 서비스별로 구성된다. 이러한 서비스 중 하나를 재사용하거나 Zeppelin을 위해 자신만의 서비스를 만들 수 있다.

[main]
 pamRealm=org.apache.zeppelin.realm.PamRealm
 pamRealm.service=sshd



Secure Cookie for Zeppelin 세션

세션 쿠키에서 HttpOnly 플래그를 설정하도록 제플린을 구성할 수 있다. 이 구성으로 제플린 쿠키는 클라이언트 쪽 스크립트를 통해 액세스할 수 없으므로 대부분의 XSS(Cross-Site Scripting) 공격을 차단한다.

cookie = org.apache.shiro.web.servlet.SimpleCookie
cookie.name = JSESSIONID
cookie.secure = true
cookie.httpOnly = true
sessionManager.sessionIdCookie = $cookie

그 외에 ZeppelinHub, Knox SSo등의 Realm관련 설정을 할 수 있다.

참고 : https://zeppelin.apache.org/docs/0.8.0/setup/security/shiro_authentication.html#active-directory




2. USERS

Users 섹션에서는 정적 사용자 계정을 정의할 수 있다. 사용자 계정의 수가 매우 적거나 사용자 계정을 런타임에 동적으로 만들 필요가 없는 환경에서 유용하다.


위와 같이 설정포맷은 username = password, role1, role2 .... roleN 이다.

[users]

admin = 1234, admin

kail = pwd1, role1

jack = pwd2, role2, role3


users파트 암호를 일반 텍스트로 만들지 않으려면 해시 알고리즘(MD5, Sah1, Sah256 등)을 사용하여 암호화할 수 있다. 기본적으로 암호 문자열은 Hex 인코딩이며, Base64 인코딩으로도 구성할 수 있다.




3. ROLES

Roles파트의 예시는 아래와 같다.

[roles]
admin = *
hr = *
finance = *
group1 = *




4. URLS

기본적으로 user파트에 정의된 모든 사용자는 아파치 제플린의 인터프리터 설정, 인증 정보 및 구성 정보를 공유할 수 있다. 경우에 따라 사용 사례를 위해 이러한 정보페이지를 숨기고 싶을 수 있다. 

Shiro는 URL 기반 보안을 제공하므로 conf/shiro.ini에서 아래 줄에 주석을 달거나 압축을 해제하여 정보를 숨길 수 있다.


변경전

[urls]

/api/interpreter/** = authc, roles[admin]
/api/configurations/** = authc, roles[admin]
/api/credential/** = authc, roles[admin]


변경후

[urls]

/api/interpreter/** = roles[admin]
/api/configurations/** = roles[admin]
/api/credential/** = roles[admin]


위와 같이 설정하면 admin roles가 아닌 모든 계정은 Interpreter, Configuration, Credential 페이지 접근이 불가하다.















[ zeppelin permission ]

각 노트마다 접근권한을 지정해주어 해당노트의 crontab이나 쿼리, 대쉬보드 추가 삭제 등 유저마다 노트에 대한 권한을 달리 줄 수 있다.

아래 이미지와 같이 우측상단의 자물쇠 그림을 눌러 설정한다.









예를 들어 user1이 Note1을 Read만하고 쿼리실행이나 다른 작업을 못하게 하려면 Owners설정은 admin, Reader는 user1으로 설정한다.( Writers랑 Runners는 자동으로 Owners설정값을 따른다.)

또한 다른유저 user2는 Readers권한도 없으므로 로그인해도 해당 Note1이 보이지 않는다.


Readers권한이 있는 User가 다른 권한접근시 알림 메세지가 나온다.








결과적으로 제플린의 인증과 접근권한은 Shiro.ini파일의 users, roles, urls파트 설정과 자물쇠버튼의 Permission설정으로 어느 정도 가능하다. 그러나 유저가 많아 파생되는 그룹이 커지고 동적 유저또한 필요하다면 Realms manager 설정또한 추가되야 할 것이다.  


2020년 11월 10일 화요일

Hive [6] - Json데이터 컨트롤 (json to hive)


Hive에서 Json파일 컨트롤


1. get_json_object

hive 0.7.0 이하로는 아래와 같이 사용한다.










[ 쿼리문 ]

SELECT

    get_json_object(StudentsOneLine, '$.StudentDetails.FirstName'),

    get_json_object(StudentsOneLine, '$.StudentDetails.LastName')

FROM StudentsOneLine;




2. json_tuple 사용

{"memberId":817090,"campaigns":[{"id":"40718","amount":"10"},{"id":"40801","amount":"26"},{"id":"40584","amount":"0"},{"id":"40685","amount":"0"}],"eventTime":"1604847624784","createdAt":"2020-11-09:00:00:25"}

위와 같은 json파일이 있다고 하면 hive 0.7.0이상부터는 json_tuple함수를 이용하여 json데이터를 추출한다.


[ 쿼리문 ]

SELECT memberid, id, amount, eventtime

from tableName 

LATERAL VIEW JSON_TUPLE(campaigns) campaigns as id, amount;




3. Explode

그러나 데이터가 아래와 같이 String 타입이 아니고 Int타입 Json이라면

{"memberId":817090,"campaigns":[{"id":40718,"amount":10},{"id":40801,"amount":26},{"id":40584,"amount":0},{"id":40685,"amount":0}],"eventTime":1604847624784,"createdAt":"2020-11-09:00:00:25"}

아래와 같은 에러가 나타난다.

Error while compiling statement: FAILED: UDFArgumentException json_tuple()'s arguments have to be string type

그럴땐 Explode함수를 사용하여 Json을 추출한다.


[ 쿼리문 ]

SELECT memberid, ca.id, ca.amount, eventtime

from tablename

LATERAL VIEW EXPLODE(campaigns) campaigns as ca


[ 결과 ]








그외로, 

4. 사용자 지정 SerDe사용

Hive에서는 json, csv뿐 아니라 커스텀으로 만들어 SerDe를 사용할 수 있다.

참조 URL : https://web.archive.org/web/20190217104719/https://blogs.msdn.microsoft.com/bigdatasupport/2014/06/18/how-to-use-a-custom-json-serde-with-microsoft-azure-hdinsight/


5. 프로그래밍

Python, Java를 이용하여 Json파일을 컨트롤 한다.



참조 :

https://docs.microsoft.com/ko-kr/azure/hdinsight/hadoop/using-json-in-hive

2020년 11월 8일 일요일

Hive [5] - 조인 (Join)


테이블 간의 Join은 부하가 매우크므로 스키마설계시 Join을 하지 않도록 구성해야 한다.

하이브에서 조인 사용시 왼쪽에서 오른쪽 FROM절 순서로 쿼리가 실행되므로 일반적으로 가장 데이터가 큰 테이블을 맨 오른쪽(마지막)에 실행되도록 쿼리를 짠다. 


* HUE이용시 

  • Error while processing statement: FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.mr.MapredLocalTask

와 같은 오류시 SET hive.auto.convert.join=false 로 설정



[ Join 명령문 ]

   table_reference JOIN table_factor [join_condition]
   | table_reference {LEFT|RIGHT|FULL} [OUTER] JOIN table_reference
   join_condition
   | table_reference LEFT SEMI JOIN table_reference join_condition
   | table_reference CROSS JOIN table_reference [join_condition]



[ Example 테이블 ]

직원테이블 (CUSTOMER)

+----+----------+-----+-----------+----------+ 
| ID | NAME     | AGE | ADDRESS   | SALARY   | 
+----+----------+-----+-----------+----------+ 
| 1  | Ramesh   | 32  | Ahmedabad | 2000.00  |  
| 2  | Khilan   | 25  | Delhi     | 1500.00  |  
| 3  | kaushik  | 23  | Kota      | 2000.00  | 
| 4  | Chaitali | 25  | Mumbai    | 6500.00  | 
| 5  | Hardik   | 27  | Bhopal    | 8500.00  | 
| 6  | Komal    | 22  | MP        | 4500.00  | 
| 7  | Muffy    | 24  | Indore    | 10000.00 | 
+----+----------+-----+-----------+----------+

주문테이블 (ORDERS)

+-----+---------------------+-------------+--------+ 
|OID  | DATE                | CUSTOMER_ID | AMOUNT | 
+-----+---------------------+-------------+--------+ 
| 102 | 2009-10-08 00:00:00 |           3 | 3000   | 
| 100 | 2009-10-08 00:00:00 |           3 | 1500   | 
| 101 | 2009-11-20 00:00:00 |           2 | 1560   | 
| 103 | 2008-05-20 00:00:00 |           4 | 2060   | 
+-----+---------------------+-------------+--------+



1. INNER JOIN [ 내부 조인 ]







RDBMS와 개념은 같지만 하이브는 동등조인(EQUI-JOIN)만을 제공한다.

( ON절에 = 만 사용)


[ 쿼리문 ]

SELECT c.id, c.name, c.age, o.amount

FROM customer JOIN orders o

ON c.id = o.customer_id

WHERE o.amount> 1500 AND o.amount< 3000;


SELECT c.id, c.name, c.age

FROM customer JOIN orders o

ON c.id = o.customer_id AND c.salary = o.amount

where c.name='khilan';


SELECT t1.var1, t1.var2, t2.var3

FROM table1 t1 JOIN table2 t2 ON t1.var1 = t2.var1

                     JOIN table3 t3 ON t1.var1 = t3.var1



[ 첫번째 쿼리문 결과 ]

+----+----------+-----+--------+ 
| ID | NAME     | AGE | AMOUNT | 
+----+----------+-----+--------+ 
| 2  | Khilan   | 25  | 1560   | 
| 4  | Chaitali | 25  | 2060   | 
+----+----------+-----+--------+



2. LEFT SEMI-JOIN











  • 오른쪽테이블에서 ON에 일치하는 레코드를 찾으면 더 이상 찾는 행동을 멈추고 왼쪽테이블의 데이터를 반환한다. 
  • 따라서 내부조인보다 빠르다.
  • 하이브는 RIGHT SEMI-JOIN은 지원하지 않는다.

[ 쿼리문 ]

SELECT t1.var1, t1.var2, t1.var3

FROM table1 t1 LEFT SEMI JOIN table2 t2

ON t1.var1 = t2.var1 AND t1.var2 = t2.var2;



3. LEFT(RIGHT) OUTER JOIN










  • Left Outer Join : Table1에 있는 모든 행과 Table2에 함께 있는 행을 얻는다.
  • Rigth Outer Join : Table2에 있는 모든 행과 Table1에 함께 있는 행을 얻는다.


[ 쿼리문 ]

SELECT c.id, c.name, o.amount, o.date

FROM customers c

LEFT OUTER JOIN orders o

ON c.id = o.customer_id;


[ 결과 ]

+----+----------+--------+---------------------+ 
| ID | NAME     | AMOUNT | DATE                | 
+----+----------+--------+---------------------+ 
| 1  | Ramesh   | NULL   | NULL                | 
| 2  | Khilan   | 1560   | 2009-11-20 00:00:00 | 
| 3  | kaushik  | 3000   | 2009-10-08 00:00:00 | 
| 3  | kaushik  | 1500   | 2009-10-08 00:00:00 | 
| 4  | Chaitali | 2060   | 2008-05-20 00:00:00 | 
| 5  | Hardik   | NULL   | NULL                | 
| 6  | Komal    | NULL   | NULL                | 
| 7  | Muffy    | NULL   | NULL                | 
+----+----------+--------+---------------------+



4. FULL OUTER JOIN 












  • left table과 right table의 합집합을 얻는다. left table에는 데이터가 있고 right table에는 없는 경우 null로 표현된다.


[ 쿼리문 ]

SELECT c.id, c.name, o.amount, o.date

FROM customers c

FULL OUTER JOIN ORDERS o

ON c.id = o.customer_id;


[ 결과 ]

+------+----------+--------+---------------------+ 
| ID   | NAME     | AMOUNT | DATE                | 
+------+----------+--------+---------------------+ 
| 1    | Ramesh   | NULL   | NULL                | 
| 2    | Khilan   | 1560   | 2009-11-20 00:00:00 | 
| 3    | kaushik  | 3000   | 2009-10-08 00:00:00 | 
| 3    | kaushik  | 1500   | 2009-10-08 00:00:00 | 
| 4    | Chaitali | 2060   | 2008-05-20 00:00:00 | 
| 5    | Hardik   | NULL   | NULL                | 
| 6    | Komal    | NULL   | NULL                |
| 7    | Muffy    | NULL   | NULL                |  
| 3    | kaushik  | 3000   | 2009-10-08 00:00:00 | 
| 3    | kaushik  | 1500   | 2009-10-08 00:00:00 | 
| 2    | Khilan   | 1560   | 2009-11-20 00:00:00 | 
| 4    | Chaitali | 2060   | 2008-05-20 00:00:00 | 
+------+----------+--------+---------------------+



5. UNION ALL

하이브 Join의 On절에서는 Or 조건의 사용을 할 수 없다. 그럴 때 UNION ALL절 이 쓰는데 예시는 아래와 같다.


  • 변경전

SELECT * 

FROM table1 t1 JOIN table2 t2

ON (t1.val1=t2.val1) or (t1.var2=t2.var2);


  • 변경후

SELECT * 

FROM table1 t1 JOIN table2 t2

ON t1.val1=t2.val1

UNION ALL

SELECT * 

FROM table1 t1 JOIN table2 t2

ON t1.var2=t2.var2;





참조 :

https://www.tutorialspoint.com/hive/hiveql_joins.htm