ELK Spring Data 연결

자바|2024. 4. 21. 22:15
728x90

 

간단히 새로 만들일이 있어서 집에서 심심풀이 삼아 이번엔 highlevel API 또는 이후 버전인 java API 등등 뭐쓸까 고민하다가 highlevel은 사실상 버려졌고 java API로 하자니 하위호환이 쫌 그렇고 해서 스프링 data에 포함된 API를 써서 해봤다.

 

레퍼넌스 사이트 보고 ( https://docs.spring.io/spring-data/elasticsearch/reference/elasticsearch/template.html )

하는 중인데... 레퍼사이트에 있는 초기화 소스만 하면 에러가 발생 한다.

"Missing [X-Elastic-Product] header. Please check that you are connecting to an Elasticsearch instance, and that any networking filters are preserving that header."

 

이런 에러 인데 찾아보면 헤더에 X-Elastic-Product 이키를 넣어서 만족시켜라 인데 대강 찾아보면 일반 restclient 관련 내용만 있어서 스프링 데이터에 맞춰서 만들어 보았다. 단순 초기화 용이고 인증은 패스한 버전이니 참고.

 

 

Elasticsearch Operations :: Spring Data Elasticsearch

When a document is retrieved with the methods of the DocumentOperations interface, just the found entity will be returned. When searching with the methods of the SearchOperations interface, additional information is available for each entity, for example t

docs.spring.io

    @Override
    public ClientConfiguration clientConfiguration() {

        HttpHeaders httpHeaders = new HttpHeaders();
//        httpHeaders.add("X-Elastic-Product", "elasticsearch");
        return ClientConfiguration.builder()
                .connectedTo("localhost:9200")
                .withDefaultHeaders(httpHeaders)
                .withClientConfigurer(ElasticsearchClients.ElasticsearchClientConfigurationCallback.from(
                        httpClientBuilder -> httpClientBuilder
                                .disableAuthCaching()
                                .setDefaultHeaders(List.of(new BasicHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString())))
                                .addInterceptorLast((HttpResponseInterceptor) (response, context) -> response.addHeader("X-Elastic-Product", "Elasticsearch")
                                )
                ))
                .build();
    }

댓글()

groovy Json 한글 제어시 UTF8 escape 변환안되게 하기

자바|2023. 10. 24. 23:52
728x90

기록용으로 간단하게 작성

NIFI  그루비 사용시 아무래도 스크립트 지원이 제한적이다 보니 외부 jar import 해결하는 경우가 많다.

json 제어시 내부 기본인 JsonSlurper JsonBuilder JsonOutput 등등 많이 사용하게 되는데 한글데이터가 있을 경우 

escape 코드로 변경되는 경우가 있다. /u00f4 등등 말이다.

 

아래 코드 참조하면 된다. 대충 기록용이라 테스트 코드 대강 박아 둔다.

핵심은 StringEscapeUtils.unescapeJavaScript(JsonOutput.toJson(aa)) 이것이다.

처리를 안해주면 /uxxxx 형태의 현기증으로 한글이 출력 된다.

import groovy.json.JsonOutput
import groovy.json.JsonSlurper
import groovy.json.StringEscapeUtils

static void main(String[] args) {



  def jsonslurper = new JsonSlurper()
  def object = jsonslurper.parseText('{"name":"하하","age":30,"cars":["Ford","BMW","Fiat"]}')

  def aa = new HashMap();
  aa.put("name", "하누킹");


    StringEscapeUtils.unescapeJavaScript(JsonOutput.toJson(aa))
    println StringEscapeUtils.unescapeJavaScript(JsonOutput.toJson(aa))
}

'자바' 카테고리의 다른 글

ELK Spring Data 연결  (1) 2024.04.21
Groovy 이미지 변환 코드  (0) 2023.07.30
루씬 숫자형 인덱싱 출력 9.3.0 기준  (0) 2022.10.07
elasticsearch basic auth 인증 코드  (0) 2022.10.01
vscode 이클립스 단축키 똑같이 하기  (0) 2022.08.07

댓글()

Groovy 이미지 변환 코드

자바|2023. 7. 30. 18:13
728x90

현재 모처에서 대규모 문서 검색 시스템(50t 규모) 구축 프로젝트를 진행 중 이다.

고객의 요청으로 문서에서 이미지 추출 미리보기 기능이 필요 한데 외부 필터를 사용해 추출 하다 보니 이미지 포멧이 멋대로 나와 몇가지 처리가 필요 하다.

 

이미지 추출 -> 이미지 파일 정리(외부 도구가 몇개 이하 추출 제한이 없다(이미지 갯수 만큼 모두 추출)) 10개 이상 삭제 ->

이미지 변환 

 

프로세스가 필요 하다. 해당 프로세스는 대략 아래의 흐름(대충 예시로 만든거라 실제 만들면 더 많은 플로우나 기능 필요) 으로 진행 하면 된다.

뭐튼 중요한건 저게 아니고 이미지 처리를 해야 되다 보니 스크립트 실행이 필요 하게 되었다.

NIFI 자체에는 이미지 처리 프로세스가 없다.

 

처음에는 파이썬으로 executecommand(외부 실행 호출)를 통해 해결할려고 했으나 폐쇄망의 특성으로 인해 외부 whl이 필요 한데 os 버전 등 등이 막장이라 오히려 더 불편해지는 상황이 필요 해서 자바로 개발해서 통jar 실행 형태로 해결할려고 보던 도중 자바의 경우 간단한 변환 작업은 외부 import 없이 해결이 가능 했다.

 

외부 import가 필요 없다는거에서 착안 groovy 로 하면 되지 않을까 싶어서 간단히 짜봤더니 역시 된다.

아래는 나이파이 관련 내용은 없고 이미지 변환 내용만 있다. (나중에 수정)

 

테스트 구동 해본 결과 에러 없이 정상적으로 잘 변환 된다. 업무에 적용 후 스크립트는 나이파이용으로 변환 후 다시 기록 하겠다.

 

목적에 맞춰 발과 깃코파일럿으로 짯다. 엉성한거 잘알고 있다....


import javax.imageio.ImageIO
static void main(String[] args) {

    flowFile = session.get()
    if(!flowFile) return

    def dirPath = flowFile.getAttribute('dirPath')
    def file = new File(dirPath)
    def files = file.listFiles()

    for(f in files) {
        def splitFile = f.getName().split("\\.")

        if( splitFile[0].length() > 3)   {
            f.delete()
        }
        else
        {
            if(splitFile[1].toLowerCase().equals('bmp')){
                def image = ImageIO.read(f)
                ImageIO.write(image, "jpg", new File(dirPath + "/" + splitFile[0] + ".jpg"))
                f.delete()
            }
        }
    }

    flowFile = session.putAttribute(flowFile, "ImageTransferPath", dirPath)
    session.transfer(flowFile, REL_SUCCESS)
}

 

아래표는 읽어들일수 있는 이미지 타입들이다.

댓글()

루씬 숫자형 인덱싱 출력 9.3.0 기준

자바|2022. 10. 7. 03:16
728x90

아리랑 형태소 분석기 소스를 보다 루씬 간단히 색인 및 검색을 구현해보면 어떨까 싶어서 색인기랑 간단한 검색기능을 만들어봤다. (구현이라기 보단 복붙이 더 가깝지만..)

 

문자타입은 검색 질의시 잘나오나 숫자타입이 나오질 않았다. 인터넷을 대강 찾아보니 대강 아래의 형태가 나왔다. 문제는 최신버전(루씬 라이브러리 9.3.0 사용) 에서 바꼇는지 int든 long이든 double이든 등등 생성자 지원을 하지 않는다. 바이트를 지원하길래 바이트로 넣었더니 바이트로 색인된다... 일단은 모든 필드에 대해 출력이 목적이기에 구글링을 좀 더 해보았지만 딱히 답이 안보였다.

           FieldType fieldType = new FieldType();
           fieldType.setStored(true);

           Field field = new Field("age",String.valueOf(hannu.getAge()).getBytes() ,fieldType);
           document.add(field);

참고로 아래와 같이

문자형의 경우  Field.Store.YES 해당을 지원 하여 간편하게 가능 하다. 

숫자의 경우 아래와 같이 색인시 출력을 지원하지 않는다. 당연히 옵션도 기능이 없다.

document.add(new StringField("id", hannu.getId(), Field.Store.YES));

document.add(new LongPoint("age", hannu.getAge() ) );

 

해결)

열심히 구글링 하다가 그냥 소스상에서 뒤져서 해결 했다. 그냥 소스부터 찾을껄... 습관을 바꿔야 하나? 하긴 구글링이 맞는 경우도 있으니 꼭 바꿀필요까지는 없겠지만...

아무래도 최상단의 소스는 예전버전 방법 같고 최신 루씬 LIB에서는 아래와 같은 형태로 하면 되는듯 하다.

document.add( new StoredField("age",hannu.getAge())  ) ;

 

위의 3개는 인터넷에서 찾은 방법인 바이트로 넣었을때 (물론 해당블로그에서 바이트로 변환 하지는 않았다. 숫자타입 그대로 넣을 방법이 없어서 내가 바꿧다)  맨밑에는 StoredField 사용하여 숫자로 잘들어간걸 볼 수 있다. 

 

엘라스틱 검색과 엔지니어링만 미친듯이 파고들었던 지난날의 나를 반성하며 루씬도 좀 봐두면 엘라스틱 이해에 도움이 크게 될듯 하다.

 - id : [stored,indexed,tokenized,omitNorms,indexOptions=DOCS<id:a1>, stored,indexed,tokenized,omitNorms,indexOptions=DOCS<name:aa1>, stored<age:[31 31]>]
 - id : [stored,indexed,tokenized,omitNorms,indexOptions=DOCS<id:a1>, stored,indexed,tokenized,omitNorms,indexOptions=DOCS<name:aa1>, stored<age:[31 31]>]
 - id : [stored,indexed,tokenized,omitNorms,indexOptions=DOCS<id:a1>, stored,indexed,tokenized,omitNorms,indexOptions=DOCS<name:aa1>, stored<age:[31 31]>]
 - id : [stored,indexed,tokenized,omitNorms,indexOptions=DOCS<id:a1>, stored,indexed,tokenized,omitNorms,indexOptions=DOCS<name:aa1>, stored<age:11>]

 

Store.YES : 검색시 내용이 나오게함
Store.NO : 검색시 내용이 안나오게함 
Store.COMPRESS : 압축 저장 함 (글 내용이 크거나, binary 파일)

indexOptions 도 꽤 여러가지가 있다. 해당 내용은 나중에 공부좀 더하고나서 포스팅 하자.

 

Store.COMPRESS 최신기준 안보인다 YES NO 만 doc에서 확인 찾아보면 나오것지 이것도 나중에..

 

 

댓글()

elasticsearch basic auth 인증 코드

자바|2022. 10. 1. 15:16
728x90

이전 회사에서 구버전을(7.5.1) 사용하는데다 oss버전을 사용하여 인증을 딱히 신경안쓰고 쓰다가 최신 버전 할려니 인증이 필요 하다. 예전 엘라스틱 협력사 다닐때 썻던 인증 코드가 있지만 버전이 많이 올라온 만큼 다시 간단히 작성해봤다. 

 

엘라스틱 doc상 소스가 생각보다 친절하지 않아 개발이라기 보단 조합이긴 하지만 대략 이형태로 가져다 쓰면 크게 문제 없다.

 

같은거 여러번 하기 싫어서 기록성으로 남겨 둔다.

    public ElasticsearchClient getCon() throws Exception {
	//엘라스틱 초기 구동 후 생성된 인증서 그대로 쓰면 된다.
        Path caCertificatePath = Paths.get("D:/elk/elasticsearch-8.4.2/config/certs/http_ca.crt");
        CertificateFactory factory =
                CertificateFactory.getInstance("X.509");
        Certificate trustedCa;
        try (InputStream is = Files.newInputStream(caCertificatePath)) {
            trustedCa = factory.generateCertificate(is);
        }

        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        //인증에 사용할 아이디 패스워드
        credentialsProvider.setCredentials(AuthScope.ANY,
                new UsernamePasswordCredentials("elastic", "Qa5_TIoB5I0wu+ii*syq"));
		
        KeyStore trustStore = KeyStore.getInstance("pkcs12");
        trustStore.load(null, null);
        trustStore.setCertificateEntry("ca", trustedCa);
        SSLContextBuilder sslContextBuilder = SSLContexts.custom()
                .loadTrustMaterial(trustStore, null);
        final SSLContext sslContext = sslContextBuilder.build();
        RestClientBuilder builder =RestClient.builder(
                        new HttpHost("localhost", 9200, "https")) //ip port https
                .setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
                    @Override
                    public HttpAsyncClientBuilder customizeHttpClient(
                            HttpAsyncClientBuilder httpClientBuilder) {
                        return httpClientBuilder.setSSLContext(sslContext)
                                .setDefaultCredentialsProvider(credentialsProvider);
                    }
                });

        // Create the low-level client
        RestClient restClient = builder.build();

        // Create the transport with a Jackson mapper
        ElasticsearchTransport transport = new RestClientTransport(
                restClient, new JacksonJsonpMapper());

        // And create the API client
        ElasticsearchClient client = new ElasticsearchClient(transport);

        return client;
    }

중간에  아이디 패스워드의 경우 엘라스틱 초기 구동시 해당화면이 출력 된다. 

해당 가져다 써도 되고 id/pw 초기화 하여 해당 써도 된다. 로컬디버깅 용도라 그냥 그대로 사용했다.

 

'자바' 카테고리의 다른 글

Groovy 이미지 변환 코드  (0) 2023.07.30
루씬 숫자형 인덱싱 출력 9.3.0 기준  (0) 2022.10.07
vscode 이클립스 단축키 똑같이 하기  (0) 2022.08.07
알파벳 배열 만들기  (0) 2022.08.05
java stream 사용 주의할점  (0) 2022.07.28

댓글()

vscode 이클립스 단축키 똑같이 하기

자바|2022. 8. 7. 01:04
728x90

vscode 확장 마켓에서 이클립스 키맵을 설치 하면 된다.

Ctrl+Shift+X <= 마켓바로가기 단축키

 

'자바' 카테고리의 다른 글

Groovy 이미지 변환 코드  (0) 2023.07.30
루씬 숫자형 인덱싱 출력 9.3.0 기준  (0) 2022.10.07
elasticsearch basic auth 인증 코드  (0) 2022.10.01
알파벳 배열 만들기  (0) 2022.08.05
java stream 사용 주의할점  (0) 2022.07.28

댓글()

알파벳 배열 만들기

자바|2022. 8. 5. 01:41
728x90

별 코드는 아니지만 스트림과 람다의 편리함을 가볍게 느껴본 코드

더편한 방법도 많겠지만 일단 요로케

	public static void main(String[] args) {
		char[] al = new char[26];
		IntStream.rangeClosed(65, 90).forEach(  x -> al[x - 65] = (char) x );
		System.out.println(al);
	}

댓글()

java stream 사용 주의할점

자바|2022. 7. 28. 02:38
728x90

Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed

스트림을 재사용 하면 다음과 같은 에러가 난다. 스트림은 한번만 사용 가능하다. 재사용 불가

		File[] hidden = new File("d:/").listFiles(File::isFile);
		
		Stream<File> stream = Arrays.stream(hidden);
		stream.forEach(System.out::println);
		
        //error 발생
		stream.sorted(Comparator.reverseOrder()).forEach(System.out::println);

 

 

댓글()