2024년 6월 6일 목요일

Spring Boot와 MyBatis 환경에서 롤백이 되지 않는 문제

 상황은 여러 개의 insert가 있는 경우, 앞의 쿼리는 정상적으로 insert되었지만

 뒤의 insert가 실패할 때 앞의 쿼리가 롤백되지 않고 insert된 상태로 남아 있는 문제였다. 


원인은 MyBatis의 autocommit이 기본적으로 true로 설정되어 있어 발생한 문제였다.

쿼리가 실행될 때마다 autocommit이 실행되어 롤백이 되지 않는 현상이 있었다.


해결책으로는 SqlSessionFactory를 직접 받아서 autocommit을 false로 설정하고, 

try-catch 블록을 사용해 명시적으로 롤백을 선언하는 방법을 사용했다.


// SqlSessionFactory를 주입받습니다.

private final SqlSessionFactory sqlSessionFactory;


...


@Transactional(rollbackFor = Exception.class)

public void 메소드() {

    // autocommit을 false로 설정하여 SqlSession을 생성합니다.

    SqlSession sqlSession = sqlSessionFactory.openSession(false);


    try {

        // 여러 insert 작업을 수행합니다.

        insert;

        insert;

    } catch (Exception ex) {

        // 예외 발생 시 롤백을 수행합니다.

        sqlSession.rollback();

        throw new RuntimeException(ex);

    } finally {

        // 세션을 닫아줍니다.

        sqlSession.close();

    }

}


SqlSession을 통해 직접 롤백 처리를 했기 때문에 @Transactional 어노테이션은 필요 없을 것 같다.

 

2022년 2월 11일 금요일

mysqldump 중 에러 발생. ERROR 1102 (42000): Incorrect database name '#mysql50#.gnome2'

아래와 같이 mysql 전체 백업을 진행하려고 하였다.

mysqldump -uroot -p'daims102938!' --all-databases > mysqldump.sql

에러가 발생.
ERROR 1102 (42000): Incorrect database name '#mysql50#.gnome2'

mysql data path로 가서 ls -al 로 전체 디렉토리를 확인하면 .gnome2와 .mozilla 디렉토리가 숨어있다.

mysql은 data path에 있는 디렉토리를 database로 인식한다. 그래서 .gnome2와 .mozilla를 database로 인식하였기 때문에 발생한 문제다.

원인은 리눅스를 gui로 설치하고 mysql계정을 만든 후 해당 계정을 mysql의 data path로 등록했기 때문이다.

mysql 계정으로 gui환경으로 접속 할 일이 없기 때문에 해당 디렉토리를 삭제하여 정상 처리 하였다.

2021년 12월 13일 월요일

OCR 인식률 비교. 테서렉트 vs paddleocr vs easyocr vs 카카오 api vs < 네이버 api


최근 디아블로2 레저렉션을 시작 했다. 예전과 다르게 유니크 아이템 외에도 확인 해야 하는 아이템들이 많았다.

그런 정보를 다 찾고 확인 하는 게 힘들었다. 

디아블로 아이템의 아이템명이나, 속성들을 감별해서 미리 등록해 놓은 DB와 비교하여 가지고 있어야 할 아이템을 판별하는 프로그램을 만들고 싶었다.

결론은 실패. OCR 문자 인식부터 막혔다.

OCR 인식에 총 3일을 투자 했는데, 이틀을 테서랙트(tesseract)에 투자했다.  


테서렉트

인식률 향상을 위해 gray 변환, medianBlur로 노이즈 제거, thresholding, erosion, dilation 등 온갖 기법을 다 써도 인식률이 크게 향상되지는 않았다.

psm 옵션과 oem옵션을 아무리 조절해도 인식률은 크게 향상 되지 않았다.

디아블로2의 폰트 자체가 일반적인 폰트가 아니다 보니 인식률이 떨어 지는 것으로 보인다.

디아블로 폰트를 새로 학습하여 인식을 해 보기로 했다.

블리자드에서 공식적으로 제공하는 폰트는 없고 비슷하게 만든 폰트는 있었다.

이중에 kodia만 한글을 지원해서 사용했다.

학습에는 jTessBoxEditor를 사용했다. 

일단 학습완료는 되긴 하는 데, 오류가 나는 부분이 많다.

APPLY_BOXES: boxfile line 1/가 ((104,3153),(145,3193)): FAILURE! Couldn't find a matching blob

그래도 완료된 모델로 돌려 보았으나 여전히 인식률은 좋지 못했다.

학습이 제대로 안 된 것 같다.

이틀동안 이 삽질을 하고 있으니 저 오류 나는 것도 찾기 싫어졌다. 테서랙트는 포기.


EasyOCR

다음으로 시도한 건 EasyOCR. 이거 꽤 좋다. 설치도 쉽고, 사용법도 굉장히 쉽다. 인식률 자체도 테서렉트보다 확실히 좋다.

이미지 전처리를 시도한 거랑, 안한 거랑 크게 인식률 향상은 없었다.

다만 내가 원하는 정도의 인식률은 안 되었다.


API

이쯤되면 그냥 돈내고 사용하는 API를 사용해볼까하는 생각이 들었다.

테스트 해본 API는 카카오랑 네이버

카카오 ocr api 테스트

네이버 ocr 테스트 - CLOVA OCR

네이버는 테스트를 위해서 이름, 이메일, 사업체를 등록해야 한다. 좀 꺼림칙했지만 일단 테스트만 해보기 위해 넣었다.

결과는 네이버의 압승. 단 2군데만 조금 틀린 결과를 보여줬다.

카카오 OCR은 생각보다 좋지 않았다. EasyOCR보다 못한 것 같다.



주관적인 OCR 인식률 비교

테서렉트 == paddleocr < 카카오 api < easyocr < 네이버 api


인식에 사용한 이미지



@Scheduled 어노테이션 파라미터를 환경변수로 사용하기

@Scheduled  어노테이션으로 10초마다 실행하는 스케쥴은 아래와 같이 쉽게 만들 수 있다.

@Scheduled(fixedDelay = 10000)
public void scheduleTask() {


여기서 10000 값을 환경변수로 적용하려고 하면 fixedDelay는 final long 타입이여야 등록 가능한데,  환경변수로 가져오는 값은 final로 처리 할 수가 없다.

그럴때는 아래처럼 fixedDelayString을 사용하면 된다.

  @Scheduled(fixedDelayString = "${myscheduler.period}")
  public void scheduleTask() {

2021년 11월 25일 목요일

자바에서 퍼센트율(나누기)을 구할 때 유의사항.

일부값 / 전체값 * 100   X 

100d * 일부값 / 전체값 O


long part = 1;
long total = 3;

double ok = 100d * part / total;
double no = part / total * 100;

System.out.println(ok);
System.out.println(no);

33.333333333333336
0.0

1 / 3 = 0.333333 이다.

'part / total' 은 항상 정수형을 반환한다. part과 total의 타입이 long 타입이기 때문에 묵시적 형변환을 통해 끝수를 버리고 long타입으로 변환 된다.

만약 part나 total이 double 타입이라면 정상적으로 0.33333을 반환한다.

그래서 처음 100d를 통해 double 타입으로 반환하라고 명시 하면 오류 없이 퍼센트 결과를 얻을 수 있다.

2021년 9월 15일 수요일

수식없는 Isolation Forest 분석

 이상 탐지는 '정상'이 아닌 데이터를 식별하는 것이다. 여기서 '정상'의 정의는 관찰되는 현상과 속성에 따라 다르다.

이상 탐지는 정상을 정의하고 그 안에 속하지 않는 모든 것을 비정상으로 판별한다.


기본적으로 정상을 정의 하는 방법은 통계적 방법(statistical methods), 분류(classification ) 또는 클러스터링(clustering)을 사용하지만 프로세스 자체는 동일하다. 

정상을 정의하고 다른 모든것은 비정상으로 판별하는 것이다.

이러한 방식은 비정상을 감지하는 데, 최적화 되어 있지 않고, 정상을 찾는 데에 최적화되어 있다. 그로 인해 너무 많은 오탐이나 너무 적은 비정상이 감지 될 수 있다.

또 계산의 복잡성으로 인해 저차원 이나 작은 크기의 데이터에 적합하다.


Isolation Forest 알고리즘은 위 두가지 문제를 해결하고 이상현상을 감지하는 데 효율적이고 정확한 방법을 제공한다.

Isolation Forest의 핵심원리는 의사 결정 트리(decision tree)를 생성하여 이상을 '격리'하는 것이다.

격리에 필요한 분할 수가 작은 값은 이상 데이터로 볼 수 있다.


여러번의 분할을 거친 데이터는 정상이라고 판별한다.

이상 데이터는 단 4번의 분할로 격리 되었다.


정상 데이터를 분리하기 위해서는 수많은 분할(depth)이 필요한 데 반해, 이상 데이터는 정상 데이터에 비해 훨씬 낮은 분할만을 필요로 한다.

분할은 무작위(random)으로 발생한다. 여기서 분할 수는 이상 점수(anomaly score)을 생성하는 데 사용된다.

이상 점수는 하나의 데이터를 격리하기 위해 사용된 분할 수의 평균이다. 이상 점수, 즉 분할 수의 평균보다 낮은 분할 수를 이상이라고 판별한다.




서브샘플링

정상 데이터가 이상 데이터에 가까울 수록 격리가 어려워 잘못 된 판별을 할 수 있다. 이 때 

서브샘플링을 이용하면 알고리즘을 효율을 높일 수 있다.

Isolation Forest 알고리즘은 전체 데이터 세트가 아닌 서브샘플링 된 데이터 세트에서 더 잘 작동한다. 


성능 향상

이상 탐지는 depth가 낮은 값을 판별하므로 하나의 데이터를 격리하기 위해 깊게 들어갈 필요가 없다. 그렇기에 일정한 깊이에 제한을 걸어 성능을 향상 시킬 수 있다.

이 값은 log2(nodes_count)을 사용한다. 이는 노드에서 생성할 수 있는 적절한 이진 트리의 평균 높이이다.



Isolation Forest 는 수직, 수평 방향으로만 분할 하기 때문에 잘못된 Scoring 이 발생할 가능성이 있다. 이를 해결하기 위해 Extended isolation forest 알고리즘을 사용한다. 다만 연산량은 더 많다.


참조

https://medium.com/@arpitbhayani/isolation-forest-algorithm-for-anomaly-detection-f88af2d5518d

https://en.wikipedia.org/wiki/Isolation_forest

2021년 8월 27일 금요일

AttributeError: 'Sequential' object has no attribute 'predict_classes'

 텐서플로우의 예제를 colab을 사용하지 않고 다운 받아서 돌리려고 할 때 문제 발생.

공식 문서의 예제에는 "!pip install -q tensorflow-gpu==2.0.0-rc1" 명령어로 텐서플로우 버전을 지정해서 다운로드 한다.

이걸 무시하고 최신버전(2.6.0)의 tensorflow를 설치해서 나는 오류. 

predict_classes 는 2021-01-01 이후에 제거됨.


https://androidkt.com/get-class-labels-from-predict-method-in-keras