ElasticSearch Index 삭제 방법

$ curl --request DELETE "elastic_search_url/index" --user ID:PW

ElasticSearch 인덱스의 특정 데이터 삭제 방법

$curl --request POST "elastic_search_url/index/_delete_by_query" --user ID:PW --data /
"
{
    "query":{
          "match":{
                "컬럼명":"조건"
          }
    }
}
"

이 때, --data부분은 한줄로 써야 한다. 

예시:

$curl --request POST "elastic_search_url/index/_delete_by_query" --user ID:PW --data "{\"query\":{\"match\":{\"id\":\"hongildong@gmail.com\"}}}"

 

오늘은 백준 3052번 문제를 풀자! 해당 문제를 봤을 때, 바로 떠오른 방법이 두 가지가 있다.

MkWeb을 개발하면서 HashMap을 엄청나게 썼기 때문에, 첫 번째로 HashMap이 떠올랐고, 그 다음으로 Queue를 이용한 풀이가 떠올랐다.

해시맵의 경우, 중복되는 키를 허용하지 않기 때문에 나머지를 구한 다음에 HashMap에 각각 넣어준 뒤, HashMap의 사이즈를 반환하면 끝이다. 너무 쉽기 때문에, Queue를 이용하여 문제를 풀이하려 한다.

사실 큐를 이용하나 ArrayList, Stack 등 다른 자료구조를 이용하나 풀이는 비슷하지만, 큐의 풀이가 더 직관적이기 때문에 큐를 선택했다.


이쯤 되면 나머지 수를 구하는 것은 쉬우니, 설명은 넘어가도록 하겠다.

val = 입력값 % 42

우리는 큐에 값을 하나 씩 넣어줄 예정인데, 이전에 큐에 이미 값이 존재하는지 확인해야 한다. 이 때, 값이 존재하지 않는다면 값을 추가하고, 존재한다면 해당 값은 따로 추가하지 않을 것이다.

이때 '하나의 큐로 어떻게 가능하지?'라는 의문이 들텐데, 당연히 두 개의 큐를 사용할 것이다. (물론, 하나는 배열, 하나는 큐 등 어떤 형태를 취하든 상관 없으나, 위에서 말한대로 큐가 직관적이기 때문에 큐를 사용할 것이다.)

mainQueue: 나머지가 저장될 큐
tempQueue: mainQueue에 존재하지 않는 val들을 임시적으로 저장할 큐

매 회차마다 mainQueue로부터 tempQueue로 하나씩 옮겨담을 것이다. 이 때, val이 mainQueue에 존재하는지 확인하고, 존재하지 않는다면 값을 추가할 것이다.

따라서 mainQueue에서는 dequeue가 주로 사용될 것이며, tempQueue에는 enqueue가 주로 사용될 것이다.

While size of mainQueue > 0 Then
    peek is mainQueue.dequeue();
    If peek is not val Then
        tempQueue.enqueue(peek);
    End If
End While

수도 코드를 표현하려 했는데.. VB의 아련한 기억이...

while 반복문이 끝나면, queue를 tempQueue로 바꿔주고, queue에 val을 추가해주면 된다. val을 추가하는 이유는 while문 내에서 val을 제외한 값들만 옮겨 넣었기 때문에, mainQueue에는 val이 없다.

최종적으로 mainQueue의 size를 출력해주면 해당 문제는 끝!


전체 코드

import java.io.*;
import java.util.*;

public class Number3052 {
    public static void main(String args[]) throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        Queue<Integer> queue = new LinkedList<>();
        for(int i = 0; i < 10; i++) {
            int val = (Integer.parseInt(bufferedReader.readLine())) % 42;
            Queue<Integer> tempQueue = new LinkedList<>();
            while(queue.size() > 0) {
                int peek = queue.poll();
                if(peek != val){
                    tempQueue.add(peek);
                }
            }
            queue = tempQueue;
            queue.add(val);
        }

        System.out.println(queue.size());
    }
}

결과는 정답!

 

[Java 코딩테스트] 백준 10818 문제풀이 / 배열 없이 최소 최대 구하기

이번엔 백준 10818번 문제를 풀려한다. 이 문제는 굳이 [배열]에 분류되었어야 하나 싶은 문제다. 따라서 배열을 쓰지 않고 푸는 방법, 배열을 쓰고 푸는 방법 총 두 가지로 풀 예정이다. 우선 지금

dev-whoan.xyz

지난 글에 이어서 이번 글은 배열을 이용해 최소 최대를 구할 것이다.

아니 근데 아무생각 없이 Bubble Sort를 이용해서 문제를 풀었더니 시간초과가 발생했다. 아 ㅋㅋ 부끄럽다 ㅋㅋ

이게 무슨일이고!

아니 근데 ㅋㅋㅋ QuickSort를 했을 때도 시간초과가 발생했다. 이게 무슨일이고!

남은건 merge sort인가..

Merge Sort는 정상적으로 정답이 나오는 것 보니, QuickSort의 최악의 경우가 n^2이라 그런 것 같다. 아마 테스트케이스에 정렬이 거의 다 되어있는 녀석이 있는거겠지.. 휴


문제풀이

여튼! 본론으로 돌아가서 문제풀이를 해 보자.

문제의 내용은 똑같으니, 앞 글에서 확인해주길 바라며 이 글에서는 본의아니게 Merge Sort에 대해 다루겠다

MergeSort, Divide and Conquer

MergeSort, 병합정렬은 쪼개고 합치는 행위로 수행된다.

Divide it!

정렬하고자 하는 배열 혹은 리스트가 주어지면, 더 이상 쪼갤 수 없을 때 까지 쪼갠다. 그리고 나서 다시 합쳐야 하는데, 이 때 더 이상 쪼갤 수 없는 단위까지 쪼갰기 때문에 두 수만 비교하여 정렬하면서 다시 배열을 만들면 된다.

2개를 넘어가는 수에서 합칠때 비교 방법은 다음과 같다.

M번째 요소: 좌측 혹은 우측에서 증가한 자리. 예를 들어, 좌측에서 1번째 요소를 이미 썼다면 M번째 요소는 2번째. 우측도 마찬가지. 이 때, 좌측과 우측의 M번째는 각각 독립적이다.

1. 좌측 배열의 인덱스가 마지막 까지 갔다면, 우측 배열의 M번째 요소를 선택한다.
2. 우측 배열의 인덱스가 마지막 까지 갔다면, 좌측 배열의 M번째 요소를 선택한다.
3. 좌측 배열의 값이 우측 배열의 값보다 작다면 좌측 배열의 M번째 요소를 선택한다.
4. 우측 배열의 값이 좌측 배열의 값보다 작다면 우측 배열의 M번째 요소를 선택한다.

코드를 보면 알겠지만, 각각의 요소를 모두 비교하여 선택하는 방식이다.

이미지 출처: https://qvault.io/golang/merge-sort-golang/

이 때, Merge Sort의 복잡도는 O(n logn)이 된다. 이 때, O(n)은 배열 전체에 대한 시간이고, O(log n)은 전체에 대하여 절반으로 나누었기 때문이다.

$$ T(N) = 2 * T(N/2) + N $$ 이고, N/2를 대입하면 $$ T(N/2) = 2 * T(N/4) + {N/2} ... $$가 된다. 반복하여 이를 정리하면, $$ T(N) = 2^n * T( {N / 2^n }) + n*N $$


최종 코드

import java.util.Scanner;

public class Number10818Arr {
    public static void main(String args[]){
        Scanner scan = new Scanner(System.in);
        int N = scan.nextInt();
        int arr[] = new int[N];
        for(int i = 0; i < N; i++){
            arr[i] = scan.nextInt();
        }
        int arr2[] = new int[N];
        sort(arr, 0, N-1, arr2);
        System.out.println(arr[0] + " " + arr[N-1]);
    }

    static void sort(int A[], int low, int high, int B[]){
        if(low >= high) return;

        int mid = (low + high) / 2;

        sort(A, low, mid, B);
        sort(A, mid+1, high, B);

        int i=low, j=mid+1;
        for(int k = low; k <= high; ++k){
            if(i > mid)
            	B[k] = A[j++];
            else if(j > high)
            	B[k] = A[i++];
            else if(A[i] <= A[j])
            	B[k] = A[i++];
            else
            	B[k] = A[j++];
        }

        for(i = low; i <= high; ++i)
        	A[i] = B[i];
    }
}

결과는 정답!

Merge Sort에 관한 글은 새로 정리해서 추가로 올리겠다.

이번엔 백준 10818번 문제를 풀려한다. 이 문제는 굳이 [배열]에 분류되었어야 하나 싶은 문제다.

따라서 배열을 쓰지 않고 푸는 방법, 배열을 쓰고 푸는 방법 총 두 가지로 풀 예정이다.

우선 지금은 배열을 쓰지 않고 풀 것이다. 테스트 케이스가 몇 개인지 주어졌기 때문에, 해당 횟수만큼 숫자를 입력받고, 최대 최소를 결정하면 된다.

최솟값은 1000001, 최댓값은 -1000001로 초기화시킨다.
그 이유는 이 값들은 입력될 범위보다 크거나 작기 때문에, 어떤 수도 1000001보다 작고, -1000001보다 크기 때문이다.

위처럼 최소, 최댓값을 초기화 시키고, 앞으로 들어오는 수에 대하여 최소보다 작다면 최솟값을 갱신시킨다. 마찬가지로 최대보다 크다면 최댓값을 갱신시킨다.

이를 통해 배열에 굳이 숫자를 집어넣지 않고도 계산이 가능하다.


최종 코드

import java.util.Scanner;

public class Number10818 {
    public static void main(String args[]){
        Scanner scan = new Scanner(System.in);
        int N = scan.nextInt();
        int min = 1000001, max = -1000001;
        for(int i = 0; i < N; i++){
            int cur = scan.nextInt();
            min = (Math.min(cur, min));
            max = (Math.max(cur, max));
        }

        System.out.println(min + " " + max);
    }
}

결과는 정답!

문제 설명

오늘은 백준 1110번 문제를 풀이하려한다. 사실 코딩 자체는 쉬운데 말이 어려워서..(일부러 어렵게 낸건가..)

그래서 주어진 문제를 내가 조금 정리해봤다.

1. 정수 base가 주어진다. (0 <= base <= 99)
2. base가 10보다 작다면, 앞에 0을 붙여 두 자리 수로 만들고, 각 자리의 숫자를 더한다.
3. base의 일의 자리 숫자와 앞에서 구한 합의 가장 오른쪽 수를 이어 붙여 새로운 수 calc를 만든다.
4. base와 calc가 같다면 프로세스를 종료시킨다.

이 때, 2번의 앞 내용을 빨간줄로 그어 놓은 이유는 다음과 같다.

한 자리 숫자 1은 01로 쓸 수 있다.
한 자리 숫자 2는 02로 쓸 수 있다.
...
한 자리 숫자 n은 0n으로 쓸 수 있다.

이제 base에 대하여 일의 자리 수와 십의 자리 수를 구할 것인데, 이는 나머지 연산으로 쉽게 구할 수 있다. 본문에 가장 오른쪽 자리 수(일의 자리 수)가 먼저 나왔기 때문에, A를 일의 자리 수, B를 십의 자리 수를 표현하는 데 사용할 것이다.

따라서 A와 B는 다음과 같다.

A = base % 10;
B = base / 10;

이제 이 A와 B를 가지고 새로운 calc를 구할 것인데, 3번을 보면 "일의 자리 숫자와 앞에서 구한 합"을 구해야 한다.

일의 자리 숫자는 A이고, "앞에서 구한 합"은 2번을 보면, "각 자리의 숫자를 더한다"기 때문에, A+B가 된다. 여기에 대하여, 가장 오른쪽 수 즉 일의 자리 수이고, 따라서 calc는 다음과 같다.

calc = A + ( (A+B)%10 );

이 calc를 base와 비교하여 종료하면 된다.


최종 코드

import java.util.Scanner;

public class Number1110 {
    public static void main(String args[]){
        Scanner scan = new Scanner(System.in);
        int base = scan.nextInt();
        int calc = base;
        int A = 0, B = 0;
        int repeat = 0;
        do{
            A = calc % 10;
            B = calc / 10;
            calc = (A*10)+((A+B)%10);
            repeat++;
        }while(base != calc);
        System.out.println(repeat);
    }
}

 

결과는 정답!

MkWeb 프레임워크에 로그인과 관련된 Authorization 기능을 제공하기 위해 JWT를 사용하려고 결정했다.

 

[Authorization] 프레임워크 권한 설정 / JWT for MkWeb

MKWeb에 로그인 기능을 구현할 때, Session/Cookie를 이용하여 구현할지, 구현한다면 어떤 방식으로 현재의 MKWeb과 결합할 수 있을 지 많은 고민을 했다. 로그인이라는 것 자체가 꽤 민감한 부분인 만

dev-whoan.xyz

MkWeb의 특징 때문에, Controller마다 다른 Authorize 인증과 관련하여 어떻게 하면 좋을까 고민했다.

생각해 보니 큰 고민이 아니었던게, MkWeb의 Controller들에 각 인증관련 기능을 추가해주면 됐다.


첫 번째, Page Controllers

앞선 글에서 말한것 처럼, 페이지에 크게 "Authorize"와 관련된 속성을 추가해 줄 것이고, 그 값은 다음과 같다.

1. no: 이 페이지는 누구나 볼 수 있다.
2. part: 이 페이지에 종속된 컨트롤러 중 권한이 필요한 것이 있다.
3. yes: 이 페이지를 보려면 반드시 권한이 인증되어야 한다.

페이지 컨트롤러로 접속시켜주는 녀석은 결국 MkDispatcher기 때문에, MkDispatcher의 제일 마지막 부분에 ConnectionChecker를 이용한 getPageAuthorization을 통해 권한 인증 여부를 확인했다. 해당 함수는 0, 1, 2 (각각 no, part, yes에 대응된다.)의 값을 리턴해주고, 2가 아니라면, 페이지를 보여주면 된다.


두 번째, SQL Controllers

SQL Controller가 제일 필요한 곳은 바로 MkWeb의 Custom Tag인 tagSEL다.

tagSEL의 최상단에 HttpServletRequest 객체를 이용하여 authorization이 설정되었는지 보고, 설정되어 있지 않다면 Unauthorized 401을 반환해주면 끝이다.


세 번째, API Controllers

SQL Controller와 마찬가지로, API Controllers는 최초에 Authorization을 확인한 뒤, 검증되지 않았다면 취소시키면 된다. 와! API를 만들 때 가장 코드를 많이 먹던 녀석이 바로 parameter중 어딘가에 포함되어있을 key를 찾는 것이었는데, authorization을 확인함으로써 정말 간단해졌다! 오예!

음... 사실 지난주 까지 쉬기로 했는데 이번주에 작은누나가 휴가라..ㅋㅋ이번주까지 널널하게 할거다! 

이거 올리면 0.0.9로 버전 올려야징

오늘 m1 맥북 에어에 사용할 외장 ssd를 샀다. 맥북 ssd 용량이 256밖에 안됐고, 무엇보다 윈도우<->맥 간의 파일 이동이 생각보다 귀찮아서 ssd를 마련했다. 근데,, 가격이,,ㅠㅠ,,과거에 누나가 동일제품 살 때는 10만원이었는데,, 50%나 올랐다..15만원.......휴...

더 최신 제품인 T7도 있는데, T5를 선택한 이유는 다음과 같다.

1. 가격이 비싸다. T7제품은 20만원이고, T5는 15만원이다.
2. 내가 사용중인 벨킨 USB 허브가 3.1밖에 지원하지 않는다.
3. T7의 속도를 모두 사용할 만큼 큰 용량의 파일을 사용하지 않는다.

다음 맥은 포트가 늘어날 예정이라는데, 해당 제품에 C to C로 사용하면 어떨까 생각 해봤지만, 해당 내용은 애플이 공식적으로 얘기한 게 아니라서,, 그냥 T5로 샀다.

제품 박스와 개봉샷

제품의 박스와 구성품은 위 사진과 같다. 검정색 제품으로 구매 했는데, 파란색과 금색은 맥북과 너무 안어울릴 것 같아서....

일단 2.5인치 SSD인 만큼 굉장히 작고 가볍다. 제품의 이론상 속도는 USB 3.1포트를 이용했을 때 Up to 540MB/s라는데, 사실 이론은 실제 사용환경과 다르기 때문에 딱히 기대하진 않는다.

나는 이렇게 물려쓰기 때문에 느리면 느렸지 이론속도는 안나올 것이다. ㅋㅋ


SSD 유틸리티 설치

일단 T5를 맥북에 꽂으면 이렇게 생긴 아이가 생기고, 클릭하면 설치파일이 동봉되어 있다.

우리는 가운데 .pkg로 끝나는 파일을 설치하여야 한다. 이 때!! M1 유저(>=OS BigSur)는 다른 설치파일을 받아야 한다.

기존 SSD에 들어있는 파일로 설치하면 인식이 안된다.(이걸로 30분 날렸다..)

https://www.samsung.com/semiconductor/minisite/ssd/download/portable/

 

Portable SSD Products | Download | Samsung V-NAND SSD

Download Tools, software, and documents for Samsung Portable SSDs. Brochure, Warranty, and User Manual for Samsung Portable SSD (external storage) T5 and T3.

www.samsung.com

위 링크를 들어가서 Portable SSD Software for T5를 찾은 뒤, (The macOS Big Sur user's only)라고 표시된 설치파일을 받아주면 된다.

기존 동봉되어있던 설치파일로 아무리 설치해도 인식 안되는 이유가 있었다..

설치파일이 시키는대로 다 해도, 포터블 SSD가 인식 안될것이다. 이 때, [시스템 환경설정 -> 보안 및 개인정보 보호]로 이동하여, 아래 사진처럼 자물쇠를 눌러주고, 시스템 확장 프로그램 활성화를 눌러주면 된다.

이 때, 시동 보안 정책이 완전 보안으로 되어있을 경우, 이를 수정하라는 문구가 뜨는데, 시키는대로 하면 된다. (해당 부분은 스크린샷을 찍을수가 없어서 생략하겠다..ㅠㅠ)

인식완료!

그러고 나면 인식이 완료된다!


속도 측정

디스크를 사면 속도측정은 반드시 해줘야 하는 법! 어.. 그런데 결과가 생각보다..안좋다. 400MB/s 정도는 기대했는데, 훨씬 못미치는 쓰기 330MB/s & 읽기 310~330MB/s 나온다. 혹시 허브가 문제인가 해서 맥북 단자에 직접 꽂아봤지만, 읽기 속도가 380MB/s로 오른것이 전부. 아래 사진의 왼쪽이 허브에 연결, 오른쪽이 맥북에 직접 연결한 속도다.

음..ㅋㅋ 뭐..ㅋㅋ 그냥 써야지...


약 두달 간 제품을 꾸준하게 썼고, 느낀점은 다음과 같다.

1. 발열은 없다. 뭐,, 좋다!

2. 넣고 다닐게 필요하다. 전용 파우치가 없어서, 제품만 노트북 파우치에 함께 들고 다니는데, 맥북에 기스갈까봐 무섭다. 그래서 따로 파우치를 사던가 해야 할듯...

3. 속도 빠르다. 당연한 얘기지만, 330MB/s 는 결코 느린 속도가 아니다. 전혀 사용하면서 지장이 없었다. 간혹 프로젝트 발표와 같은 영상도 넣고 다녔는데(보통 500메가, 크면 1.5기가 정도), 느리다는 느낌이 전혀 없다.

총점 5.0/5.0! (워낙 검증된 제품이니 ㅎㅎ)

2438번 문제

오늘은 별찍는 문제를 풀어보려 한다. 2438번 문제 같은 경우에는 for문을 중첩하여 풀 수 있고, 어렵지 않으니 코드를 바로 공유하겠다.

import java.util.Scanner;

public class Number2438 {
	public static void main(String args[]) {
		Scanner scan = new Scanner(System.in);
		int T = scan.nextInt();
		for(int i = 0; i < T; i++) {
			for(int j = 0; j <= i; j++)
				System.out.print("*");
			System.out.println();
		}
	}
}

그런데 우리는 해당 문제를 풀기 위해 Dynamic Programming을 이용할 수도 있다. 동적 계획법이라고도 하는데, DP로 흔히 부른다.

DP를 쉽게 설명하자면, "앞선 문제를 풀어놓고 다음 문제를 푸는 것"이라고 할 수 있겠다. 감이 잘 안올텐데, DP와 관련된 글을 따로 작성하여 본 게시글에 첨부할 테니, 더 궁금하다면 해당 글을 봐 달라.


그러면 어떻게 DP를 별 찍기에 이용할 수 있느냐? 문제의 출력을 보면, 별이 하나씩 순차적으로 늘어나는 것을 볼 수 있다.

즉, "앞선 레벨의 별은 이미 찍혀있고, 뒤 레벨에는 앞의 별에 하나를 추가해주면 된다." 라는 발상을 할 수 있다. 

주어진 T 크기의 배열을 만들고, 앞에서부터 별을 채워나가면 된다. 또한 재귀 호출 형식으로 만들 예정이고, base는 다음과 같다.

base case: index == 배열의 길이 Then 배열 반환
recursive case: 배열[index-1] + "*"

또한 별은 앞 레벨부터 찍을 것이기 때문에, 최초의 index는 0이 된다. 이 때, 배열[0-1] 은 존재하지 않기 때문에 따로 index가 0인 경우에 대하여 array[0] = "*"을 해준다.

따라서 전체 코드는 다음과 같다.

import java.util.Scanner;

public class Number2438DP {
	public static void main(String args[]) {
		Scanner scan = new Scanner(System.in);
		int T = scan.nextInt();
		String[] star = new String[T];
//		createStar(star, 0);
//		for(int i = 0; i < star.length; i++) {
//			System.out.println(star[i]);
//		}
		setStar(star);
        
        for(int i = 0; i < star.length; i++){
			System.out.println(star[i]);
		}
	}
	
	static void setStar(String[] arr){
		for(int i = 1; i < arr.length; i++)
			arr[i] = arr[i-1] + "*";
	}
    
	static String[] createStar(String[] arr, int index) {
		if(index == arr.length)
			return arr;
		
		if(index == 0)
			arr[index] = "*";
		else
			arr[index] = arr[index-1] + "*";
		
		return createStar(arr, index+1);
	}
}

보면 String[] star= new String[T];를 통해 주어진 크기만큼 별의 문제를 풀 String 배열을 선언하고, 해당 배열의 0번 index부터 별을 채워나간다.

arr[index] = arr[index-1] + "*";

해당 줄을 보면, 현재 index의 배열은 index-1의 배열에 *을 더해준다.

결과는 정답!


궁금해서 포문으로 돌렸을 때랑 비교해 봤다.

아래가 DP 위가 포문

음..근데 생각해보니 백준 서버에 따라 차이가 있을것 같다..ㅋㅋ

+ Recent posts