예제가 포함된 Hive 조인 및 하위 쿼리 튜토리얼

⚡ 스마트 요약

Hive 조인은 일치하는 열을 기준으로 두 개 이상의 테이블의 행을 결합하고, 서브쿼리는 하나의 쿼리 안에 다른 쿼리를 중첩합니다. 따라서 여기서는 일반 텍스트 파일에서 로드한 두 개의 샘플 테이블을 사용하여 두 가지 모두를 설명합니다.

  • 🧱 두 개의 예시 표: sample_joins에는 고객 정보가, sample_joins1에는 주문 정보가 저장되어 있으며, 두 테이블은 공통된 ID 열을 기준으로 조인됩니다.
  • 🔗 네 가지 결합 유형: 내부, 왼쪽 외부, 오른쪽 외부 및 전체 외부 조인은 각각 일치하지 않는 행의 집합을 다르게 유지합니다.
  • NULL은 공백을 나타냅니다. 외부 조인은 일치하는 항목이 없더라도 행을 반환하며, 누락된 쪽의 모든 열을 NULL로 채웁니다.
  • 🔁 순서가 중요합니다. 조인은 교환 법칙이 성립하지 않고 좌측 결합 법칙이 성립하므로, 스왑(swap)을 사용해야 합니다.ping 테이블이 외부 조인 결과를 변경합니다.
  • 🧮 서브쿼리는 쿼리를 중첩합니다. 서브쿼리는 FROM 절이나 WHERE 절에 작성되며, 외부 쿼리는 서브쿼리가 반환하는 값에 따라 달라집니다.
  • 📜 TRANSFORM은 스크립트를 포함합니다: 내장 함수가 적합하지 않을 경우 사용자 지정 맵 및 리듀스 스크립트는 TRANSFORM 절을 통해 실행됩니다.

Hive 조인 및 서브쿼리 예제

쿼리 결합

조인 쿼리는 두 테이블에 대해 수행할 수 있습니다. 하이브조인 개념을 명확하게 이해하기 위해 여기에 두 개의 테이블을 생성하겠습니다.

  • 샘플 조인(고객 세부 정보 관련)
  • sample_joins1 (직원이 주문한 세부 정보와 관련됨)

단계 1) 직원들의 ID, 이름, 나이, 주소, 급여를 열 이름으로 하는 "sample_joins" 테이블을 생성합니다. 아래 스크린샷은 CREATE TABLE 문과 그 확인 메시지를 보여줍니다.

Hive에서 sample_joins 고객 테이블에 대한 CREATE TABLE 문을 작성합니다.

단계 2) 데이터를 불러와 표시하는 방법입니다. 다음 스크린샷은 로드 명령과 그 뒤에 나오는 테이블 내용을 보여줍니다.

Customers.txt 파일을 sample_joins에 로드하고 로드된 행을 표시합니다.

위 스크린샷에서:

  1. Customers.txt에서 Sample_joins로 데이터 로드
  2. Sample_joins 테이블 내용 표시

단계 3) 아래 스크린샷과 같이 sample_joins1 테이블을 생성한 다음 데이터를 로드하고 표시합니다.

sample_joins1을 생성하고 orders.txt 파일을 불러와 주문 행을 표시합니다.

위 스크린샷에서 다음과 같은 사실을 확인할 수 있습니다.

  1. Orderid, Date1, Id, Amount 열을 가진 sample_joins1 테이블 생성
  2. Orders.txt에서 Sample_joins1로 데이터 로드
  3. Sample_joins1에 있는 레코드 표시

앞으로 우리는 생성한 테이블에서 수행할 수 있는 다양한 유형의 조인을 살펴보겠습니다. 그 전에 조인에 대해 다음 사항들을 고려해야 합니다.

조인 시 유의해야 할 몇 가지 사항:

  • 조인에서는 등가 조인만 허용됩니다.
  • 동일한 쿼리에서 두 개 이상의 테이블을 조인할 수 있습니다.
  • LEFT, RIGHT 및 FULL OUTER 조인은 일치하는 항목이 없는 ON 절에 대한 더 많은 제어 기능을 제공하기 위해 존재합니다.
  • 조인은 교환법칙이 성립하지 않습니다.
  • 조인은 LEFT 조인인지 RIGHT 조인인지에 관계없이 왼쪽 결합입니다.

동일성 조건은 과거 Hive의 구조를 반영합니다. Hive 2.2.0 버전부터는 ON 절에서 복잡한 표현식이 지원되므로(HIVE-15211), 현재 버전에서는 동일성이 아닌 조건도 허용됩니다. 이전 버전에서는 동일성 조건만 사용해야 하며, 그 외의 조건은 WHERE 절로 이동해야 합니다.

다양한 유형의 조인

조인에는 4가지 유형이 있습니다. 다음과 같습니다.

  • 내부 조인
  • 왼쪽 외부 조인
  • 오른쪽 외부 결합
  • 전체 외부 조인

각 유형은 아래의 두 테이블을 사용하여 설명되므로 예제 간의 유일한 차이점은 일치하지 않는 행 중 어떤 행이 남는지입니다.

내부 조인

이 내부 조인을 통해 두 테이블에 공통으로 존재하는 레코드가 검색됩니다. 아래 스크린샷에는 주문 내역이 일치하는 고객만 표시됩니다.

Hive 내부 조인 출력에서 ​​일치하는 주문이 있는 고객만 표시합니다.

위 스크린샷에서 다음과 같은 사실을 확인할 수 있습니다.

  1. 여기서는 JOIN 키워드를 사용하여 sample_joins 테이블과 sample_joins1 테이블 간에 (c.Id = o.Id) 일치 조건을 적용한 조인 쿼리를 수행합니다.
  2. 출력 결과에는 쿼리에 명시된 조건을 확인하여 선택된, 두 테이블 모두에 공통으로 존재하는 레코드가 표시됩니다.

검색어 :

SELECT c.Id, c.Name, c.Age, o.Amount FROM sample_joins c JOIN sample_joins1 o ON(c.Id=o.Id);

왼쪽 외부 결합

  • 하이브QL LEFT OUTER JOIN은 오른쪽 테이블에 일치하는 항목이 없더라도 왼쪽 테이블의 모든 행을 반환합니다.
  • ON 절에서 오른쪽 테이블에 일치하는 레코드가 없더라도 조인 결과에는 오른쪽 테이블의 각 열에 NULL 값이 포함된 레코드가 반환됩니다.

아래 스크린샷은 주문이 없는 고객을 포함하여 모든 고객이 표시되는 것을 보여줍니다.

주문 내역이 없는 고객에 대해 NULL 값을 포함하는 Hive left outer join 출력 결과

위 스크린샷에서 다음과 같은 사실을 확인할 수 있습니다.

  1. 여기서는 `LEFT OUTER JOIN` 키워드를 사용하여 `sample_joins` 테이블과 `sample_joins1` 테이블을 조인하고, 일치 조건(`c.Id = o.Id`)을 적용합니다. 예를 들어, 여기서는 직원 ID를 기준으로 삼아, 해당 ID가 왼쪽 테이블과 오른쪽 테이블 모두에 존재하는지 확인합니다. 이것이 일치 조건의 역할을 합니다.
  2. 위 출력은 쿼리에 명시된 조건에 따라 선택된 레코드를 보여줍니다. 위 출력에서 ​​NULL 값은 오른쪽 테이블(즉, sample_joins1)에서 값이 없는 열을 나타냅니다.

검색어 :

SELECT c.Id, c.Name, o.Amount, o.Date1 FROM sample_joins c LEFT OUTER JOIN sample_joins1 o ON(c.Id=o.Id)

오른쪽 외부 결합

  • HiveQL의 RIGHT OUTER JOIN은 왼쪽 테이블에 일치하는 항목이 없더라도 오른쪽 테이블의 모든 행을 반환합니다.
  • ON 절이 왼쪽 테이블에서 일치하는 레코드가 없는 경우에도 조인 결과에는 왼쪽 테이블의 각 열에 NULL 값이 포함된 레코드가 반환됩니다.
  • 오른쪽 조인은 항상 오른쪽 테이블의 레코드와 왼쪽 테이블에서 일치하는 레코드를 반환합니다. 왼쪽 테이블에 해당 열에 대응하는 값이 없는 경우 해당 위치에 NULL 값을 반환합니다.

아래 스크린샷은 이전 결과의 반전된 모습입니다. 일치 여부와 관계없이 모든 주문이 표시됩니다.

하이브 오른쪽 외부 조인 출력 키ping sample_joins1의 모든 주문 행

위 스크린샷에서 다음과 같은 사실을 확인할 수 있습니다.

  1. 여기서는 "RIGHT OUTER JOIN" 키워드를 사용하여 sample_joins 테이블과 sample_joins1 테이블 간에 (c.Id = o.Id) 일치 조건을 적용한 조인 쿼리를 수행합니다.
  2. 출력 결과에는 쿼리에 언급된 조건을 확인하여 선택된 레코드가 표시됩니다.

검색어 :

  SELECT c.Id, c.Name, o.Amount, o.Date1 FROM sample_joins c RIGHT OUTER JOIN sample_joins1 o ON(c.Id=o.Id)

전체 외부 결합

이 기능은 쿼리에 지정된 JOIN 조건을 기반으로 sample_joins 테이블과 sample_joins1 테이블의 레코드를 결합합니다.

이 함수는 두 테이블의 모든 레코드를 반환하고, 아래 스크린샷에서 볼 수 있듯이 양쪽 테이블 중 어느 한쪽에서 일치하는 값이 없는 열에 NULL 값을 채웁니다.

Hive 전체 외부 조인 출력: 두 테이블에서 일치하지 않는 행을 결합합니다.

위 스크린샷에서 다음과 같은 사실을 확인할 수 있습니다.

  1. 여기서는 "FULL OUTER JOIN" 키워드를 사용하여 sample_joins 테이블과 sample_joins1 테이블 간에 일치 조건(c.Id = o.Id)으로 조인 쿼리를 수행합니다.
  2. 출력 결과는 쿼리에 명시된 조건을 만족하는 두 테이블의 모든 레코드를 보여줍니다. 출력 결과에서 NULL 값은 두 테이블의 해당 열에 누락된 값을 나타냅니다.

검색어 :

SELECT c.Id, c.Name, o.Amount, o.Date1 FROM sample_joins c FULL OUTER JOIN sample_joins1 o ON(c.Id=o.Id)

하위 쿼리

조인은 테이블을 나란히 배치합니다. 서브쿼리는 이와는 다른 역할을 합니다. 서브쿼리는 하나의 쿼리를 다른 쿼리 안에 중첩하여, 바깥쪽 쿼리가 이미 계산된 결과를 활용할 수 있도록 합니다.

쿼리 안에 포함된 쿼리를 서브쿼리라고 합니다. 메인 쿼리는 서브쿼리가 반환하는 값에 따라 달라집니다.

서브쿼리는 두 가지 유형으로 분류할 수 있습니다.

  • FROM 절의 서브쿼리
  • WHERE 절의 서브쿼리

사용시기 :

  • 서로 다른 테이블의 두 열 값에서 결합된 특정 값을 얻으려면
  • 한 테이블의 값이 다른 테이블의 값에 의존하는 관계
  • 한 열의 값을 다른 테이블의 값과 비교 검사

구문 :

Subquery in FROM clause
SELECT <column names 1, 2…n>From (SubQuery) <TableName_Main >
Subquery in WHERE clause
SELECT <column names 1, 2…n> From<TableName_Main>WHERE col1 IN (SubQuery);

예:

SELECT col1 FROM (SELECT a+b AS col1 FROM t1) t2

여기서 t1과 t2는 테이블 이름입니다. 내부 문장은 테이블 t1에 대해 실행되는 서브쿼리입니다. a와 b는 서브쿼리에 추가되어 col1에 할당되는 열입니다. col1은 메인 테이블의 해당 열 값입니다. 서브쿼리에 있는 "col1" 열은 메인 테이블 쿼리의 col1 열 값과 동일합니다.

사용자 정의 스크립트 포함

하위 쿼리가 HiveQL만으로 데이터를 재구성하는 경우, 내장 스크립트는 행을 Hive 외부에서 작성된 코드로 전달합니다.

Hive를 사용하면 클라이언트 요구 사항에 맞는 사용자 지정 스크립트를 작성할 수 있습니다. 사용자는 이러한 요구 사항에 맞는 맵 및 리듀스 스크립트를 직접 작성할 수 있습니다. 이러한 스크립트를 임베디드 사용자 지정 스크립트라고 합니다. 코딩 로직은 사용자 지정 스크립트에 정의되며, ETL 시점에 해당 스크립트를 사용할 수 있습니다.

내장 스크립트를 선택해야 하는 경우:

  • 클라이언트별 요구 사항으로 인해 개발자가 Hive에서 스크립트를 작성하고 배포해야 하는 경우
  • Hive 내장 함수가 특정 도메인 요구 사항에 적합하지 않은 경우

이를 위해 Hive는 TRANSFORM 절을 사용하여 맵 스크립트와 리듀서 스크립트를 모두 포함합니다.

이러한 내장형 사용자 지정 스크립트에서는 다음 사항을 준수해야 합니다.

  • 각 열은 문자열로 변환되고 탭으로 구분된 후 사용자 스크립트에 전달됩니다.
  • 사용자 스크립트의 표준 출력은 탭으로 구분된 문자열 열로 처리됩니다.

내장 스크립트 예시:

FROM (
	FROM pv_users
	MAP pv_users.userid, pv_users.date
	USING 'map_script'
	AS dt, uid
	CLUSTER BY dt) map_output

INSERT OVERWRITE TABLE pv_users_reduced
	REDUCE map_output.dt, map_output.uid
	USING 'reduce_script'
	AS date, count;

위 스크립트에서 다음과 같은 점을 확인할 수 있습니다. 이는 이해를 돕기 위한 예시 스크립트일 뿐입니다.

  • pv_users는 사용자 테이블이며, map_script에 언급된 것처럼 userid와 date와 같은 필드를 포함합니다.
  • 리듀서 스크립트는 pv_users 테이블의 날짜와 개수를 기반으로 정의됩니다.

자주 묻는 질문

과거에는 불가능했습니다. Hive 2.2.0 버전부터는 ON 절에 복합 표현식을 사용할 수 있게 되어(HIVE-15211) 부등식 및 범위 조건이 작동합니다. 이전 버전에서는 ON 절에 동등성 조건만 사용해야 했으며, 다른 조건은 모두 WHERE 절에 포함해야 했습니다.

맵 조인은 더 작은 테이블을 메모리에 로드하고 리듀스 단계를 완전히 건너뜁니다. Hive는 `hive.auto.convert.join`이 true이고 테이블이 구성된 크기 임계값에 맞는 경우 자동으로 맵 조인을 선택하므로 작은 테이블과 큰 테이블을 조인하는 속도가 훨씬 빨라집니다.

이 함수는 왼쪽 테이블에서 오른쪽 테이블에 하나 이상의 일치하는 행을 중복 없이 반환하며, 오른쪽 테이블의 열은 반환하지 않습니다. 오른쪽 테이블은 ON 절에서만 참조할 수 있으며, SELECT 또는 WHERE 절에서는 참조할 수 없습니다.

부분적으로는 그렇습니다. Hive 0.13 버전부터 IN, NOT IN, EXISTS 및 NOT EXISTS 연산자는 WHERE 절에 하위 쿼리(상관 쿼리 포함)를 허용합니다. 하지만 제한 사항은 여전히 ​​존재하므로 지원되지 않는 상관 관계는 일반적으로 조인으로 다시 작성해야 합니다.

내부 쿼리는 파생 테이블이 되며, 모든 테이블은 열을 참조하기 전에 이름이 필요합니다. 따라서 예제는 닫는 괄호 뒤에 t2가 붙습니다. 별칭을 생략하면 구문 분석 오류가 발생합니다.

하나의 조인 키가 불균형적으로 많은 행을 처리하는 경우, 단일 리듀서가 대부분의 작업을 독차지하고 다른 리듀서는 유휴 상태가 됩니다. hive.optimize.skewjoin 설정을 사용하거나, 작업이 많은 키를 분리한 후 결과를 합치는 방식으로 부하를 분산할 수 있습니다.

머신 러닝 기반 도우미는 EXPLAIN 실행 계획을 읽고 파티션 필터 누락, 변환되지 않은 맵 조인 또는 잘못된 키와 같은 일반적인 원인을 표시합니다. 이 제안을 시작점으로 활용하고 실행 계획 및 실제 실행 시간과 비교하여 확인하십시오.

짧은 주석만으로도 표준 조인 및 서브쿼리 패턴을 잘 작성합니다. 엔진별 설정은 반드시 확인해야 합니다. 다른 엔진과 쉽게 혼합되기 때문입니다. Spark Hive는 SQL 또는 Presto 구문을 사용하며, 별칭이 지정되지 않은 파생 테이블과 같은 구문을 허용하지 않습니다.

이 게시물을 요약하면 다음과 같습니다.