java로 UDF 만들기2(WGS84로 국가지점번호 생성)

이번엔 우리가 사용하는 위도,경도값을 받아 국가지점번호로 바꿔주는 UDF를 java로 만들어 볼 것이다.

WGS84로 국가지점번호 생성

바꾸는 과정은 아래와 같다.

과정1. 우리가 사용하는 WGS84 좌표계 형식인 위도, 경도값을 받는다.

과정2. pyproj 라이브러리를 이용하여 UTM-K 좌표계로 변환해준다.

과정3. UTM-K 좌표계로 변환된 값들을 국가지점번호로 규칙에 맞게 변환해 준다.

규칙은 아래와 같다.


예] 나 바 9842 3400 [안면도 탕건봉의 위치]

  1. 첫째 음절을 다음과 같이 변환한다 가 => 7 나 => 8 다 => 9 라 => 10 마 => 11 바 => 12 사 => 13 예시의 경우 ‘나’이므로 8이 된다

  2. 첫번째 4자리 숫자에 0을 붙인다 예시의 경우 98420이 된다

  3. 1과 2의 결과를 순차로 합하면 898420이다. 이것은 UTM-K의 동향값(Easting)이다

  4. 두번째 음절을 다음과 같이 변환한다 가 => 13 나 => 14 다 => 15 라 => 16 마 => 17 바 => 18 사 => 19 아 => 20 예시의 경우 ‘바’이므로 18이 된다

  5. 두번째 4자리 숫자에 0을 붙인다 예시의 경우 34000이 된다

  6. 4와 5의 결과를 순차로 합하면 1834000이다. 이것은 UTM-K의 북향값(Northing)이다.


Data(table_nm : coordinates)

rtd_no xcdnt ycdnt
1 127.072387 37.571924
2 126.92708706 37.48367315
3 127.03945 37.500388
4    
5 테스트 테스트

그럼 이제 과정대로 코드를 작성해 보자.


UDF java code

필요한 라이브러리는 아래와 같다.

  • 각 버전에 맞는 hive-exec.jar

  • json-simple-1.1.jar

  • proj4j-0.1.0.jar

    (내 경우 proj4j 라이브러리는 hive에서 읽지를 못했다. 그래서 직접 소스를 찾아 클래스를 추가하였고, proj4j가 필요로 하는 라이브러리인 junit-3.8.1을 추가하였다.)

코드는 아래와 같다.

package hiveudf;

import org.apache.hadoop.hive.ql.exec.UDF;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.osgeo.proj4j.BasicCoordinateTransform;
import org.osgeo.proj4j.CRSFactory;
import org.osgeo.proj4j.CoordinateReferenceSystem;
import org.osgeo.proj4j.ProjCoordinate;


public class getGridId extends UDF {	
	public String evaluate(String x, String y) throws Exception {
		
		String first_char_list = "{\"7\": \"\", \"8\": \"\", \"9\": \"\", \"10\": \"\", \"11\": \"\", \"12\": \"\", \"13\": \"\"}";
		String second_char_list = "{\"13\": \"\", \"14\": \"\", \"15\": \"\", \"16\": \"\", \"17\": \"\", \"18\": \"\", \"19\": \"\", \"20\": \"\"}";
		
		if(x != null && x != "" && y != null && y != "") {
			try {
				// WGS84 -> UTM-K
				CRSFactory factory = new CRSFactory();
				CoordinateReferenceSystem srcCrs = factory.createFromName("EPSG:4166");  // WGS84
				CoordinateReferenceSystem dstCrs = factory.createFromName("EPSG:5179");  // UTM-K 
				
				BasicCoordinateTransform transform = new BasicCoordinateTransform(srcCrs, dstCrs);
				ProjCoordinate srcCoord = new ProjCoordinate(Double.parseDouble(x), Double.parseDouble(y)); 
				ProjCoordinate dstCoord = new ProjCoordinate(); 
		
				transform.transform(srcCoord, dstCoord);  // 좌표변환 
				Long x_utmk = Math.round(dstCoord.x);
				Long y_utmk = Math.round(dstCoord.y);
				
				// UTM-K -> 국가지점번호
				if(x_utmk >= 0 && y_utmk >= 0) {  // (x, y)좌표가 (0, 0)일때 음수인 경우 방지
					// 코드를 자르기 위해 문자열로 변환
					String x2 = Long.toString(x_utmk);
					String y2 = Long.toString(y_utmk);
					
					//   한자리 제거
					String x3 = x2.substring(0, x2.length()-1);
					String y3 = y2.substring(0, y2.length()-1);
					
					// 국가지점번호 문자 변환
					String first_char_code = x3.substring(0, x3.length()-4);
					String second_char_code = y3.substring(0, y3.length()-4);
					JSONParser parser = new JSONParser();
					JSONObject first_char_json = (JSONObject)parser.parse(first_char_list);
					JSONObject second_char_json = (JSONObject)parser.parse(second_char_list);
					if(first_char_json.containsKey(first_char_code) && second_char_json.containsKey(second_char_code)) {  // 국가지점번호 문자 json 파일에 존재할 경우
						String first_char = (String)first_char_json.get(first_char_code);
						String second_char = (String)second_char_json.get(second_char_code);
						String first_num = x3.substring(x3.length()-4, x3.length()-1);
						String second_num = y3.substring(y3.length()-4, y3.length()-1);
						String grid_id = first_char + second_char + first_num + second_num;
						return grid_id;
					} else {
						return null;
					}
				} else {
					return null;
				}
			} catch (NumberFormatException e) {
				return null;
			}
		} else {
			return null;
		}
	}
}

이 코드에서 중요한 부분은 method의 이름이 evaluate가 되어야 한다는 점이다. UDF의 경우 클래스 내에서 evaluate라는 method를 찾아 실행하는 것 같다. 다른 이름으로 했을 경우, hive에서 no matching method for class 에러가 나온다.

다음은 만든 java 프로젝트를 Jar 파일로 패키징한다. eclipse에서 외부 라이브러리를 포함하여 패키징 하는 방법은 다음 링크를 참조하면 된다.

외부 라이브러리를 포함하여 jar파일 생성

생성한 jar 파일을 hadoop 안에 넣어준다. (hadoop에 넣지 않고 로컬의 경로로 jar 파일을 hive에 추가해 주려고 했지만 실패했다.)

$ hadoop fs -put getGridId.jar /temp/jar/

이제 hive로 가서 jar 파일을 추가하여 함수를 만들자.

(혹시 잘 안된다면 hive에서 나갔다가 들어와서 다시 해보니 정상적으로 함수가 생성되었다. 전에 메모리가 남아있었던 것으로 의심된다.)

hive> create temporary function get_grid_id as 'hiveudf.getGridId' using jar 'hdfs:///temp/jar/getGridId.jar'

test라는 함수가 새로 만들어졌다. 사용해보자.

hive> select get_grid_id('127.072387', '37.571924');  # 다바732757

결과가 주석과 같이 나오면 성공이다.

Leave a comment