2021년 8월 26일 목요일

[ Scala ] Date Rang Foreach 예시



[ Code ]

import java.time.LocalDate

import java.time.format.DateTimeFormatter


val format = DateTimeFormatter.ofPattern("yyyy-MM-dd")

val start_dt = LocalDate.parse("2020-02-01", format)

val end_dt = LocalDate.parse("2020-02-20", format)

val date_diff = end_dt.toEpochDay() - start_dt.toEpochDay()


for (i <- 0l to date_diff by 1) {

  val s = start_dt.plusDays(i)

  val f_date = start_dt.plusDays(i)

  val date = f_date.toString().replaceAll("-","")

  val date_s = f_date + " 00:00:00"

  val date_e = f_date + " 23:59:59"

  val yymm = date.slice(0,6)

  println(s)

}

import java.time.LocalDate

import java.time.format.DateTimeFormatter


val format = DateTimeFormatter.ofPattern("yyyy-MM-dd")

val start_dt = LocalDate.parse("2021-05-04", format)

val end_dt = LocalDate.parse("2021-05-31", format)

val date_diff = end_dt.toEpochDay() - start_dt.toEpochDay()




[ Result ]

2020-02-01
2020-02-02
2020-02-03
2020-02-04
...
2020-02-18
2020-02-19
2020-02-20



2021년 8월 3일 화요일

[ Algorithm ] 로또의 최고 순위와 최저 순위


문제 ]

특정조건일때 각기다른 2개의 배열이 같은 값은 몇개 가지는지를

비교하는 문제


https://programmers.co.kr/learn/courses/30/lessons/77484


순위 당첨 내용

1 6개 번호가 모두 일치

2 5개 번호가 일치

3 4개 번호가 일치

4 3개 번호가 일치

5 2개 번호가 일치

6(낙첨) 그 외

구매했던 로또로 당첨이 가능했던 최고 순위와 최저 순위를 알아보고 싶어 졌습니다.

알아볼 수 없는 번호를 0으로 표기하기로 하고, 구매한 로또 번호 6개가 44, 1, 0, 0, 31 25라고 가정해보겠습니다. 당첨 번호 6개가 31, 10, 45, 1, 6, 19라면, 당첨 가능한 최고 순위와 최저 순위의 한 예는 아래와 같습니다.


로또 당첨 번호        31 10          45 1 6         19 결과

최고 순위 번호 31 0→10  44 1 0→6 25 4개 번호 일치, 3등

최저 순위 번호 31 0→11  44 1 0→7 25 2개 번호 일치, 5등


순서와 상관없이, 구매한 로또에 당첨 번호와 일치하는 번호가 있으면 맞힌 걸로 인정됩니다.

구매한 로또 번호를 담은 배열 lottos, 당첨 번호를 담은 배열 win_nums가 매개변수로 주어집니다. 이때, 당첨 가능한 최고 순위와 최저 순위를 차례대로 배열에 담아서 return 하도록 solution 함수를 완성해주세요.


제한사항

lottos는 길이 6인 정수 배열입니다.

lottos의 모든 원소는 0 이상 45 이하인 정수입니다.

0은 알아볼 수 없는 숫자를 의미합니다.

0을 제외한 다른 숫자들은 lottos에 2개 이상 담겨있지 않습니다.

lottos의 원소들은 정렬되어 있지 않을 수도 있습니다.

win_nums은 길이 6인 정수 배열입니다.

win_nums의 모든 원소는 1 이상 45 이하인 정수입니다.

win_nums에는 같은 숫자가 2개 이상 담겨있지 않습니다.

win_nums의 원소들은 정렬되어 있지 않을 수도 있습니다.


입출력 예

lottos win_nums result

[44, 1, 0, 0, 31, 25] [31, 10, 45, 1, 6, 19] [3, 5]

[0, 0, 0, 0, 0, 0] [38, 19, 20, 40, 15, 25] [1, 6]

[45, 4, 35, 20, 3, 9] [20, 9, 3, 45, 4, 35] [1, 1]




제출 ] 


import java.util.*;
import java.util.stream.IntStream;
import java.util.stream.Collectors;
import java.util.Iterator;

class Solution {
    public int[] solution(int[] lottos, int[] win_nums) {

        int[] answer = {7,7};
        Iterator<Integer> iter = 
            Arrays.stream(lottos).boxed().collect(Collectors.toList()).iterator();
        
        while (iter.hasNext()) {
            int tmp = iter.next();
            if(IntStream.of(win_nums).anyMatch(x -> x == tmp)){
                answer[0]--;
                answer[1]--;
            }
            if(tmp == 0) answer[0]--;
        }
        
        if(answer[0]==7) answer[0] = 6;
        if(answer[1]==7) answer[1] = 6;
        return answer;
    }
}



풀이 ]

int[] answer = { 최고순위, 최저순위 } 로 7,7로 시작해 

lottos의 배열 값이 win_nums배열에 있으며 최고순위, 최저순위 각 -1씩

lottos의 배열 값이 0 이면 최고순위 -1씩 하여 반환한다. 

Ex) 5개가 맞으면 7 - 5 = 2, 즉 2등



다른 사람 풀이 ]

import java.util.Arrays;
import java.util.stream.LongStream;

class Solution {
    public int[] solution(int[] lottos, int[] winNums) {

        return LongStream.of(
            (lottos.length + 1) - Arrays.stream(lottos)
            .filter(l -> Arrays.stream(winNums).anyMatch(w -> w == l) || l == 0)
            .count(),
            (lottos.length + 1) - Arrays.stream(lottos)
            .filter(l -> Arrays.stream(winNums).anyMatch(w -> w == l))
            .count()
        ).mapToInt(op -> (int) (op > 6 ? op - 1 : op)).toArray();

    }
}


람다식으로 표현

return Stream.of( 최고순위, 최저순위).(리턴값 7일 경우 예외처리)



2021년 8월 2일 월요일

[ Kubernetes ] 아키텍처


[ 쿠버네티스 아키텍쳐 ] 


1. 컨트롤 플레인

컨트롤 플레인은 클러스터의 두뇌 역할을 하며 

사용자의 API요청, CLI, UI서비스를 제공한다.





















좀 더 자세히 살펴보면
아래 그림의 실선의 쿠버네티스 마스터 영역이 컨트롤 플레인이다.
  • etcd : 쿠버네티스 관련 메타정보를 저장하는 데이터베이스
  • kube-apiserver : 컨트롤 플레인의 프론트엔드 서버로 API요청을 처리
  • kube-scheduler : 생선된 파드를 실행할 노드를 결정
  • kube-controller-manager : 디플로이먼트와 같은 리소스 컨트롤러를 관리
  • cloud-controller-manager : 클라우드 기반 클러스터의 로드밸런서나 디스트볼륨 자원을 관리
























2. 노드 컴포넌트 

  • kubelet : 노드에 예약된 워크로드를 실행하기 위해 컨테이너 런타임관리, 모니터링
  • kube-proxy : 서로 다른 노드에 있는 파드간 통신, 네트워크 트래픽을 라우팅



3. 고가용성

  • etcd 데이터베이스는 여러 노드에 걸쳐 복제되며, 절반이상이 사용가능하면 복구가능
  • 컨트롤 플레인 장애시 App이 다운되진 않지만, 새로운 컨터에너 또는 리소스를 변경할 수 없으므로 가장 빠르게 복구해야 함
  • 고가용성을 위해 상용시 최소 3개이상의 클러스터가 필요
  • 워커노드장애시 쿠버네티스가 해당 노드의 파드들을 다른 노드로 재조정


2021년 7월 28일 수요일

[ Kubernetes ] 도커를 이용한 쿠버네티스 기본예제


[ 도커설치 ] 

sudo yum -y update

sudo yum -y install docker

docker version

sudo yum -y install git 

# demo 다운로드

git clone https://github.com/cloudnativedevops/demo


# 도커실행

sudo systemctl status docker

sudo systemctl start docker


# demo 실행

sudo docker container run -p 9999:8888 --name hello cloudnatived/demo:hello

*웹 브라우저 http://localhost:9999 로 들어가

Hello, 世界 글귀를 확인



[ 도커이미지 빌드 ]

sudo docker image build -t myhello .

sudo docker container run -p 9999:8888 myhello


# 도커 컨테이너 레지스트리

https://hub.docker.com/ 에서 도커계정생성


# 도커로그인

sudo docker login

...

Username : user_id

Password : ****

...

Login Succeeded


# 도커 이미지 푸쉬

sudo docker image tag myhello yourID/myhello

sudo docker image push yourID/myhello
















# 인터넷이 연결된 곳이라면 어디서든 내 컨테이너 이미지 사용가능

sudo docker container run -p 9999:8888 yourID/myhello




[ 쿠버네티스 설치 ]

단일클러스터에서 실행이기 때문에 minikube 설치

curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 && chmod +x minikube

sudo mkdir -p /usr/local/bin/

sudo install minikube /usr/local/bin/


* 아래와 같은 에러가 난다면

  - docker: Not healthy: "docker version --format {{.Server.Os}}-{{.Server.Version}}" exit status 1: Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/version": dial unix /var/run/docker.sock: connect: permission denied


sudo groupadd docker

sudo usermod -aG docker $USER

newgrp docker 


참조 : https://docs.docker.com/engine/install/linux-postinstall/



minikube status

만약 클러스터가 실행 중이면, minikube status 의 출력은 다음과 유사해야 한다.

host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured


정지시 

minikube stop





[ 쿠버네티스로 데모 애플리케이션 실행 ]


kubectl run demo --image=yourID/myhello --port=9999 --labels app=demo


kubectl port-forward pod/demo 9999:8888


-> 웹 브라우저 http://localhost:9999 확인

kubectl get pods --selector app=demo
NAME   READY   STATUS    RESTARTS   AGE
demo   1/1     Running   0          6m9s


# Pod삭제시

kubectl delete pod 1234-56-7890-234234-456456


# Delete all pods

kubectl delete pods --all


# 포트포워딩 후 http://yourip:9999 브라우저에서 output확인

kubectl port-forward yourDir/demo 9999:8888







2021년 7월 22일 목요일

[ Algorithm ] 폰켓몬 - Array to Set


[ 문제 ] 

https://programmers.co.kr/learn/courses/30/lessons/1845


* 제한사항

nums는 폰켓몬의 종류 번호가 담긴 1차원 배열입니다.

nums의 길이(N)는 1 이상 10,000 이하의 자연수이며, 항상 짝수로 주어집니다.

폰켓몬의 종류 번호는 1 이상 200,000 이하의 자연수로 나타냅니다.

가장 많은 종류의 폰켓몬을 선택하는 방법이 여러 가지인 경우에도, 선택할 수 있는 폰켓몬 종류 개수의 최댓값 하나만 return 하면 됩니다.


*입출력 예

nums result

[3,1,2,3] 2

[3,3,3,2,2,4] 3

[3,3,3,2,2,2] 2



[ 제출 ]

import java.util.*;

class Solution {
    public int solution(int[] nums) {

        int answer = 0;
        Set<Integer> p = new HashSet<Integer>();

        for(int e : nums)  p.add(e);
        if(p.size() > nums.length/2)
            answer = nums.length/2;
        else
            answer = p.size();

        return answer;
    }
}


[ 풀이 ]

nums의 int형 배열을 set으로 자료형변환을 통해 중복을 제거한다.

최대값은 N/2이므로 set에 담긴 요소의 갯수가 더 크다면 N/2를 반환한다.



[ 다른사람풀이 ]

import java.util.Arrays;

import java.util.stream.Collectors;


class Solution {
    public int solution(int[] nums) {

        return Arrays.stream(nums)
            .boxed()
          .collect(Collectors.collectingAndThen(Collectors.toSet(),phonekemons 
                -> Integer.min(phonekemons.size(), nums.length / 2)));
    }
}


첫번째 풀이의 기능을 자바 스트림을 이용하여 실행

코드가 좀더 간결해지고 내부반복자를 사용하기에 병렬처리가 용이하다.



2021년 6월 14일 월요일

[ Spark ] 예제코드 SBT환경에서 실행


Linux SBT Tool를 통해 프로젝트 구조를 만들었다면 

참조 : https://www.blogger.com/blog/post/edit/preview/5343302747859156115/6404446971532325983

ProjectName/build.sbt를 수정하여 버전 및 Library를 추가한다.


- Spark관련 라이브러리 추가

libraryDependencies ++= Seq(
        "org.scala-lang.modules" %% "scala-parser-combinators" % "1.1.2",
        "org.apache.spark" % "spark-core_2.11" % "2.4.0",
        "org.apache.spark" % "spark-sql_2.11" % "2.4.0",
        "org.apache.spark" % "spark-hive_2.11" % "2.4.0"
)

참고 : https://www.scala-sbt.org/1.x/docs/Library-Dependencies.html


$ sudo vi src/main/scala/Main.scala

import org.apache.spark.sql.SparkSession
object Main extends App {
  val spark = SparkSession.builder()
      .appName("Spark Hive Example")
      .enableHiveSupport()
      .getOrCreate()

  spark.sql("show databases").show()
}



# 스파크 코드작성
sudo vi src/main/scala/Main.scala

# jar파일로 빌드
sbt package

# jar파일 spark실행
spark-submit --class [클래스명] --master [local/yarn/yarn-client] [jar파일경로] [인자]

Ex)
spark-submit --class "Curator" --master local --deploy-mode client /home/ec2-user/spark/member-influencer-statistics/target/scala-2.11/member-influencer-statistics_2.11-1.0.jar '20210618' '2021-06-18'












[ Airflow ] Centos7 설치


[ 개요 ]

airflow 모듈

  • airflow webserver: 웹UI를 통해 workflow를 컨트롤 하기 위함
  • airflow scheduler: DAG 파일을 통록된 workflow를 지정된 시간에 동작시키는 역할
  • airflow worker: scheduler에 의해 할당된 workflow를 실제로 동작시킴
  • airflow kerberos(옵션) : 만약 kerberos 인증된 데이터소스(ex- 하둡)에 접근할때 커버로스 인증티켓을 주기적으로 갱신하기 위함




[ 사전설치 ]

## 파이썬 3.6 설치 및 virtualenv 설치

$ sudo yum install -y python3 python3-devel

$ sudo pip3 intall virtualenv


##추가 필요 모듈 설치

$ sudo yum install -y gcc gcc-c++ cyrus-sasl-devel mysql-devel


## https://github.com/inishchith/autoenv

## virtualenv를 편하게 사용하기 위해 autoenv 설치

## virtualenv를 활성화 하려면 매번 해당 디렉토리에 들어가서 source ./bin/activate 를 실행해줘야 한다.

## autoenv는 디렉토리 이동시 .env 파일의 유무를 확인한후 .env를 실행한다.

## 따라서 .env 파일을 만들고 virtualenv activate를 써주면 매번 activate를 해줄필요 없이 자동으로 처리된다.

$ sudo pip3 install autoenv

$ echo "source `which activate.sh`" >> ~/.bash_profile

$ source ~/.bash_profile



[ Airflow 설치 ]

$ mkdir ${airflow 설치 디렉토리}


## airflow_home 환경변수 지정, 지정된 위치에 airflow가 설치되게 된다.

$ echo 'export AIRFLOW_HOME=${airflow 설치 디렉토리}' >> ~/.bash_profile

$ source ~/.bash_profile


$ cd ${airflow 설치 디렉토리}


## 가상 환경 설치

$ virtualenv -p python3 venv

$ echo 'source $AIRFLOW_HOME/venv/bin/activate' >> .env

## airflow_home 디렉토리로 다시 접근하면 autoenv에 의해 .env가 읽히고 윗줄의 source 설정이 읽힌다.

## 아래와 같이 나와야 autoenv 설정이 제대로 된것이다.

$ cd $AIRFLOW_HOME

autoenv:

autoenv: WARNING:

autoenv: This is the first time you are about to source /${AIRFLOW_HOME}/.env:

autoenv:

autoenv:     --- (begin contents) ---------------------------------------

autoenv:     source ./venv/bin/activate

autoenv:

autoenv:     --- (end contents) -----------------------------------------

autoenv:

autoenv: Are you sure you want to allow this? (y/N) y


$ pip3 install apache-airflow==1.10.5


## initdb를 하면 초기 설정파일이 airflow_home에 생성된다.

$ airflow initdb

## dag가 저장될 디렉토리 생성

$ mkdir dags

$ ls -ah

.env  airflow.cfg  airflow.db    dags  logs  unittests.cfg  venv 


[ Airflow DB ]

DB컨트롤 툴인 DBeaver에서 SQLite를 선택하고 

Path를 airflow.db로 잡는다.


연결완료화면

















참조 : 

https://airflow.apache.org/docs/apache-airflow/stable/howto/set-up-database.html

https://louisdev.tistory.com/3