인덱스 바이너리

마지막 업데이트: 2022년 3월 7일 | 0개 댓글
  • 네이버 블로그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 트위터 공유하기
  • 카카오스토리 공유하기
바이너리 field의 파라미터

인덱스 바이너리

바이너리 로그 파일은 데이타베이스 변경(테이블 생성,삭제등) 및 테이블 변경(insert,update,delete ..) 사항들이 기록되는 바이너리 형태의 파일이다.

바이너리 로그는 로그 파일과 인덱스 파일 두개로 구성 된다. 인덱스 파일은 바이너리 로그 파일의 리스트를 인덱스 바이너리 가진 텍스트 파일로 .index 확장자를 가진다.

- my.cnf 파일에 log-bin, server-id 인덱스 바이너리 추가

[mysqld]
log-bin
server-id=1

log-bin[=basename] 에서 basename을 정의 하지 않을 경우 -bin.00000N 으로 생성됨

2. 바이너리 로그 파일 옵션

log-bin[=basenam] : 바이너리 로그 파일 이름, 절대 경로 설정 가능

max_binlog_size=N[G,M,K] : 바이너리 로그 파일의 최대 크기 지정(단위 G,M,K,bytes), default 1G, Max 값도 1G

expire_logs_days : 바이너리 로그 파일 보관 기간(일 단위), default 0, 즉 바이너리 로그를 삭제 하지 않음

binlog_cache_size : 바이너리 로그 캐쉬 크기(단위 byte), 각각의 클라이언트을 위한 할당 크기, default 32k

** 바이너리 로그 파일은 mysql이 재시작 되거나 max_binlog_size 설정값을 초과 할 경우 다음 바이너리 로그 파일이 생성됨

3. 바이너리 로그 파일 관리

3.1 바이너리 로그 파일 목록 및 현재 바이너리 로그 파일 확인

- testsvr-bin.0003 이전 파일 모두 삭제

mysql> show binary logs ;
+--------------------+-----------+
| Log_name | File_size |
+--------------------+-----------+
| testsvr-bin.000003 | 177 |
| testsvr-bin.000004 | 177 |
| testsvr-bin.000005 | 2287 |
+--------------------+-----------+
3 rows in set (0.00 sec)

- 날짜 기준 바이너리 로그 파일 삭제

4. mysqlbinlog 명령어

바이너리 로그 파일은 이름처럼 바이너리 형태로 저장이 되기 때문에 텍스트 편집기등으로 파일을 읽을 수 없다. 바이너리 로그 파일을 읽을수 있는 텍스트로 변경해 주는 명령어가 mysqlbinlog 이다

인덱스 바이너리

이전에 전화번호부 관련 프로젝트를 진행한 경험이 있다.

하지만 전화번호부에 있는 이름들을 다 선형 탐색으로 필터링하고 있었다.

사실 유저가 많지 않기 때문에 선형탐색으로 해도 특별히 문제점을 느끼지 못했다.

하지만 유저의 수가 증가할수록 선형 탐색이 아닌 이진 탐색이 필요하다는 것을 느끼게 되었다.

때문에 이 부분은 수정이 필요했다.

왜 선형 인덱스 바이너리 탐색보다 이진 탐색이 나았는지는 아래 코드 결과를 보면 정확하게 파악할 수 있다.

선형 탐색과 이진 탐색을 비교하기 위해 먼저 정렬된 배열을 준비했다.

for문을 돌려 0부터 인덱스 바이너리 1000까지의 숫자를 붙여주고 그 배열을 가지고 탐색을 진행했다.

linear 말 그대로 하나씩 탐색하며 검사하는 방법이다.

for문을 돌면서 array에 있는 하나씩 비교한다.

찾으려는 값 searchValue와 비교해서 값이 존재하면 true를 리턴하며,

값이 없는 경우 끝까지 루프를 다 돌고 나서 false를 리턴한다.

이진 탐색과 비교하기 위해 프린트 문을 찍었다.

당연히 0부터 찾으려는 인덱스 바이너리 값까지 출력된다.

30까지 출력한 후 30이 내가 찾으려는 값이랑 같으니 함수는 true를 리턴하며 끝이 난다.

재귀로 작성하는 방법도 있지만 오늘은 while을 사용해서 풀어보려 한다.

가운데 인덱스를 잡아주고 내가 찾으려는 값이 가운데 인덱스의 값보다 같으면, 작으면, 크면으로 나눈다.

가운데 인덱스의 값이랑 같다면 바로 true를 리턴하고,

가운데 인덱스의 값보다 작다면 rightIndex는 중간 인덱스의 -1 해준 값으로 변경해준다. (범위를 좁혀나가는 과정)

가운데 인덱스의 값보다 크다면 leftIndex는 중간인덱스의 +1 해준값으로 변경해준다. (이 또한 범위를 좁혀나가는 과정)

위 방법을 계속하다 보면 내가 찾으려는 값이 있는지 없는지 확인 가능하다.

while문 안에 얼마나 찍히는지 보면 5번이 찍혔다.

위 선형 탐색보다 훨씬 작은 수임을 확인할 수 있다.

그래프를 살펴보면 선형 탐색과 이진 탐색은 number of elements가 작으면 별 차이를 느끼지 인덱스 바이너리 못한다.

하지만 우측으로 갈수록 두 그래프의 폭이 커짐을 확인할 수 있다.

resource : https://www.techtud.com/sites/default/files/public/user_files/tud39880/linearSearch%20vs%20binary%20search%20diagram_0.jpg

코딩 맛집

이진 탐색 은 값이 정렬 되어 있는 상태 에서 중앙 값 을 이용해서 찾고자 하는 데이터의 위치를 탐색 하는 알고리즘 입니다. 전체 탐색 범위 ( 첫번째 인덱스, 마지막 인덱스)와 중앙 인덱스 알고 있다면, 중앙 인덱스의 값 과 찾고자 하는 데이터의 값 을 비교 해서, 더 작다면 왼쪽 만 탐색, 더 크다면 오른쪽 만 탐색 합니다. 따라서 우리는 3가지 변수 를 알고 있어야 합니다.

중앙 인덱스 : mid = (head + tail) / 2

여기서, 중앙 인덱스의 나머지 값은 버리고, 몫만 사용 합니다.

2. 이진 탐색(Binary Search) 순서

위 그림과 같이, 찾고자 하는 target 값은 9 입니다.

(target > array[mid]) 라면, head = mid + 1 업데이트

(target == array[mid]) 면, mid 를 반환해 줍니다.

이진 탐색은 탐색 범위 를 반씩 줄여 갈수 있다는 점에서 시간 복잡도 : O(logN) 입니다. 탐색 범위가 크고 데이터의 정렬 기준 이 정해져 있는 문제에서 이진 탐색(Binary Search)을 고려해 볼수 있을거 같습니다.

인덱스 바이너리

이번 포스팅은 엘라스틱 서치 사용 중

존재하는 인덱스의 매핑 필드 타입을 변경하는

1. 문제 발생 및 파악

- 엘라스틱을 사용해 데이터를 적재한 뒤 검색 쿼리 도중 문제 발생

- 사용하려는 쿼리가 데이터의 타입과 맞지 않아 검색 할 수 없다는 내용을 담고있다.

- 즉, vector scoring 검색을 사용하는데, vector가 binary형태로 입력이 되어있어야 하는데 현재 text로 맵핑되어있음

에러 문구

2. 해결 방안

- 기본적으로 한번 지정된 데이터 타입은 변경이 불가능하다.

- 여기서 제시하는 방법은 다시 데이터를 적재하지 않고, 최대한 쉽게 원하는 타입의 맵핑으로 변경하는 방법

- 기존에 데이터가 담긴 인덱스는 두고, 새로운 매핑을 가진 인덱스 패턴을 생성한다

- 엘라스틱의 reindex API를 사용하여 새로운 인덱스로 데이터를 복사한다.

[Trouble Shooting]

reindex 시 document가 많아 오래걸리면 timeout error 가 발생한다.

그럴경우, 뒤에 파라미터로 ?wait_for_completion=false를 붙여주면, 중간에 타임아웃이 나지않고 reindex가 계속 진행된다.

trouble shootin 발생화면

3. 엘라스틱에서 binary타입의 데이터 사용하는 방법

- 가장 중요한 엘라스틱 인덱스 바이너리 공식 문서 링크

Binary datatype | Elasticsearch Reference [7.5] | Elastic

The binary type accepts a binary value as a Base64 encoded string. The field is not stored by default and is not searchable: PUT my_index < "mappings": < "properties": < "name": < "type": "text" >, "blob": < "type": "binary" >> > > PUT my_index/_doc/1 < "

- 위와 같이 인덱스 생성시 "vector"필드가 검색이 안되는 문제 발생

- 다시 공식 문서로 들어가 자세히 확인 후 binary 필드의 파라미터가 존재하는 사실을 발견

바이너리 field의 파라미터

인덱스 바이너리

이 BIT는
여러가지 최대 최소 문제에서 O(N) 시간복잡도를 O(lg N)으로 줄여 준 사랑스러운 자료구조입니다.

A Fenwick tree (also known as binary indexed tree) is a data structure that can be used to implement cumulative frequency tables. It was invented by Peter Fenwick in 1994.
(Wikipedia)
1994 년에 저 사람이 개발했다고 하네요.

흔히들 Index Tree로 쓰지만. 너무 길어서 하위 본문에서는 BIT를 쓰도록 하겠습니다.

Tip : 이 자료구조의 기초는 완전이진트리입니다만,
편리하게 사용하기 위해서는 포화이진트리로 바꾸어서 구축하는 편이 낫습니다.


기본 틀은 이렇습니다.
맨 루트 노드가 전체 범위를 담당하고 각 자식이 반씩 뜯어서 범위를 나눠가지고,
단말 노드가 되면 이제 각각의 값을 고유하게 가지는 간단한 개념입니다.

반대로 말하면, 부모 노드가 자식 둘의 범위를 합쳐서 (최대를 구한다면 둘 중 큰 것을) 저장합니다.
첫번째부터 네번째까지 중의 최대를 찾고 싶으면 굳이 1,2,3,4 다 안둘러봐도 1-4의 범위를 가지는 2번째 라인의 첫번째 노드의 값을 그대로 가져오기만 하면 됩니다. 저 1-4의 범위를 가지는 노드는
'2'의 인덱스를 가지는데, 이 인덱스 부여 방법은 후에 설명하겠습니다.

또한 응용하여 만약 첫번째부터 여섯번째까지를 구한다면 1-4의 값과 5-6의 값을 비교하고
두번째부터 여덟번째까지의 최대를 구한다면 2-2, 3-4, 5-8 이중 제일 큰 값을 찾으면 되겠죠.

인덱스 부여는 다음과 같습니다. 그냥. 맨 위부터 그리고 맨 왼쪽부터 증가시켜주면 됩니다.
1,2,3,4,5,6,7,8,9. 이렇게요.
범위를 다 붙인 다음은 아래와 같습니다.


처음 보시는 분들은 잘 모르실지도 모르지만, 이진트리의 특성 중 하나인데,
왼쪽 자식의 노드는 부모의 인덱스 x2
오른쪽 자식의 노드는 부모의 인덱스 x2 +1
부모의 인덱스는 [자식의 인덱스 /2] (코딩할 때는 소수점 짤리니까 그냥 /2 하셔도 됩니다)

아까 특별히 말을 안했지만, 데이터 갯수에 따라서 트리의 사이즈가 바뀝니다.
N개일 때 일단 2의K로 표현되는 숫자 중 N보다 크거나 같은 녀석을 찾아줍니다.
그리고 사이즈를 각각 지정해 주는데,
그리고 그 구한 녀석을 M이라고 할 때, 단말 노드는 M개, 총 트리 사이즈는 M*2-1 입니다.

ex)
1 => 1
2 => 2
3~4 => 4
5~8 => 8
9~16 => 16

이 숫자가 N에 대한 M입니다. 그후 단말노드의 앞부터 차례대로 데이터를 넣어주면 세팅이 끝입니다.
i번째 데이터는 M+i-1 번방에 인덱스 바이너리 넣어주면 되는데, 예를 들면
데이터가 5개라면 M은 8이 될 테고, 단말 노드는 8개, 총 트리 사이즈는 15개가 되고,
i번 데이터를 넣을 때는 M+i-1 이니까 1번째 데이터는 8번 방. 이런 식으로

그리고 M-1부터 1로 줄여가면서 두 자식노드를 비교해서
더 크거나 작은 것을 넣는 방법으로 세팅이 끝납니다.

사실 영상으로 해보고 싶었는데 기술력이 없는 이유로 인덱스 바이너리 포기.

장황하네요. 역시 이건 말로 해야되는데, 글로 쓰면 어색합니다.
코드로 하는 게 더 편할지도 모르겠네요. 아. 범위 자르는 것도 설명 안했는디
설명이 어눌해서 그러니 코드 보고 이해하세요!


// Start
// 아아. 참고로 밑 소스는 최소값 찾는 소스입니다.
// 최대 찾고 싶으시면 INF 넣는 부분을 -INF로 해주시고 부등호들 반대로 해주시면 됩니다.


0 개 댓글

답장을 남겨주세요