diff --git a/_drafts/2020-11-22-monad.markdown b/_drafts/2020-11-22-monad.markdown new file mode 100644 index 0000000..20b1996 --- /dev/null +++ b/_drafts/2020-11-22-monad.markdown @@ -0,0 +1,117 @@ +--- +layout: single +title: "Monad" +date: 2020-11-22 11:10:03 +0900 +categories: [woowa] +--- + + + +## python monad + +monad 는 이해하기 어려운 개념이라고 악명이 높죠. + +https://www.youtube.com/watch?v=26jVysJHB-s +프레젠테이션은 별로인데 예제가 좋아서 가져왔습니다. + + +## 예시: TimedValue + +일련의 함수를 실행하고, 총 실행시간을 측정하고 싶다고 합시다. +먼저 함수의 실행 시간을 리턴하도록 만드는 decorator 를 선언합니다. + +```python +from functools import wraps +from time import sleep, time + +def time_it(f): + @wraps(f) + def wrapper(*args, **kwargs): + start = time() + result = f(*args, **kwargs) + end = time() + return result, end - start + return wrapper + +``` + +이제 이 decorator 를 함수에 씌우고 실행하면? 실행 결과와 실행시간이 리턴되겠죠? + +```python +@time_it +def fast(x): + return x + 1 + + +@time_it +def slow(x): + sleep(0.1) + return x + 1 + + +@time_it +def slow2(x): + sleep(0.1) + return x + 2 +``` + +함수를 실행하고 걸린 시간을 저장해 봅시다. + +```python +x0, time0 = fast(1) +x1, time1 = slow(x0) +x2, time2 = slow2(x1) + +total_time = sum(time0, time1, time2) +``` + +깔끔한 코드입니다만! 아쉬운 점이 조금 있습니다. + +* unpacking (x0, time0) 을 반복합니다. +* 실행 종료 후 각 time 을 따로 sum() 해야 합니다. (물론 각 함수의 개별 실행 시간이 필요하다면 이 방법을 써야 합니다.) + +이를 메소드 chaining 을 사용해서 개선해보겠습니다. 시간과 값을 갖는 클래스 +`TimedValue` 를 만듭니다. + + +```python +from functools import wraps +from time import sleep, time + + +class TimedValue: + + def __init__(self, value, time=time()): + self.value = value + self.time = time + + def bind(self, f): + ''' + f() 는 TimedValue 객체를 반환하는 함수. + bind 를 사용해서 method 를 묶습니다(chain). + ''' + timed_value = f(self.value) + new_value = timed_value.value + new_time = self.time + timed_value.time + return TimedValue(new_value, new_time) + + +def time_it(f): + @wraps(f) + def wrapper(*args, **kwargs): + start = time() + result = f(*args, **kwargs) + end = time() + return TimedValue(result, end - start) + return wrapper + + +timed_value = fast(1).bind(slow).bind(slow2) +print(timed_value.value, timed_value.time) +``` + +어때요? 더 간결하게 느껴지시나요? +그건 그런데 이게 monad 와 무슨 상관이냐구요? 방금 우리가 +monad 를 만들었잖아요! 바로 TimedValue 클래스입니다! + + diff --git a/_drafts/2021-06-20-concerning-like.markdown b/_drafts/2021-06-20-concerning-like.markdown new file mode 100644 index 0000000..042546c --- /dev/null +++ b/_drafts/2021-06-20-concerning-like.markdown @@ -0,0 +1,66 @@ +--- +layout: single +title: "좋아요에 관한 간단한 고찰" +date: 2021-06-20 11:10:03 +0900 +categories: [Python, Aws] +--- + +## 게시글에 '좋아요' +좋아요, 이게 간단해 보이지만 생각보다 엄청 복잡한 기능입니다. +퀄리티 있는 좋아요 기능을 구현하기 위해서는 다음과 같은 문제를 해결해야 합니다. + +* 새로운 '좋아요' 값은 기존 '좋아요' 값에 영향을 받습니다. (new_like = old_like + 1) + 그렇다면 동시성 문제를 해결하기 위해 Lock 을 걸어야 할까? 같은 고민을 하게 되죠. + +* 다양한 종류의 테이블에 좋아요를 할 수 있어야 합니다. 요즘 SNS 보면 댓글에도 좋아요, 게시글에도 좋아요 + 별의별 종류의 테이블에 좋아요를 할 수 있죠. 이건 RDBMS 에서 어떻게 모델링을 해야 하는 걸까요? + +* 좋아요는 쓰기보다 읽기가 훨씬 많은 데이터 입니다. 따라서 좋아요 수를 계산하기 위해 record 를 매 번 세는 것은 + 효율적이지 않습니다. 총 좋아요 값을 저장할 필요가 있습니다. + +* 운영 측면에서 좋아요 수를 가지고 통계를 내기에 편리해야 합니다. + + +## 좋아요를 구현하는 다양한 방법들 + + +### 좋아요 테이블이 수많은 테이블과 직접 foreign key 를 맺는 방법 +* likes 가 수많은 foreign key 중 하나만 값을 갖고 나머지는 NULL 일 것을 보장해야 합니다. mysql 만으로는 할 수 없고, + 코드 상에서 제한을 두어야겠죠? + + + +### Document 에 좋아요를 하는 방법 + +* 공통된 부모를 두고, 부모에 좋아요를 연결 +* NULL 인 foreign key 가 없습니다. +* 좋아요 수를 구하기 위해서 바로 likes 를 join 할 수 없고, documents 를 중간에 join 해야 합니다. +* documents 에 like_cnt 를 둘 수 있습니다. + + + + +## 운영 측면에서 통계 내기 + + +### 좋아요가 가장 많은 게시글은 무엇인가? + +간단한 쿼리로 알아낼 수 있습니다. +```sql +SELECT MAX(id) FROM likes group by article_id; +``` + + + + + + + +### 좋아요 수를 읽어들이지 않고, 바로 UPDATE 를 치는 방법 +Lock 을 걸지 않고 문제를 해결하는 아주 깔끔한 방법입니다. + + + + + + diff --git a/_posts/2020-11-22-monad.markdown b/_posts/2020-11-22-monad.markdown deleted file mode 100644 index 9d352df..0000000 --- a/_posts/2020-11-22-monad.markdown +++ /dev/null @@ -1,10 +0,0 @@ ---- -layout: single -title: "우와한 테크코스 광탈" -date: 2020-11-22 11:10:03 +0900 -categories: [woowa] ---- - -어휴 - - diff --git a/_posts/2020-12-19-Python Descriptor.markdown b/_posts/2020-12-19-Python Descriptor.markdown deleted file mode 100644 index fc2e9a9..0000000 --- a/_posts/2020-12-19-Python Descriptor.markdown +++ /dev/null @@ -1,16 +0,0 @@ ---- -layout: single -title: "NAT" -date: 2020-12-07 11:10:03 +0900 -categories: [Network] ---- - - - - - - - - - - diff --git a/_posts/2021-01-03-pyenv.markdown b/_posts/2021-01-03-pyenv.markdown deleted file mode 100644 index f798672..0000000 --- a/_posts/2021-01-03-pyenv.markdown +++ /dev/null @@ -1,8 +0,0 @@ ---- -layout: single -title: "Jekyll 시작" -date: 2019-01-16 21:21:03 +0900 -categories: [jekyll] ---- - -jekyll minimal mistake 블로그 시작! diff --git a/_posts/2021-06-20-concerning-like.markdown b/_posts/2021-06-20-concerning-like.markdown deleted file mode 100644 index b3cad5c..0000000 --- a/_posts/2021-06-20-concerning-like.markdown +++ /dev/null @@ -1,50 +0,0 @@ ---- -layout: single -title: "소연 AWS 이전" -date: 2020-11-14 11:10:03 +0900 -categories: [Python, Aws] ---- - -## 소개팅연구소 -현재 진행중인 프로젝트. - -스스로 보기 위해 포스팅 합니다! - -## Ec2 인스턴스 생성 -security group 에서 80번 포트를 여는 것! 잊지 맙시다. - - -## python 3.8 설치 -여러 버전을 쓸 계획은 없으므로 pyenv 는 생략 -링크 - - -## pip update -`pip install --update pip` -우분투 18 기본이 무려 pip 9... 지금 최신은 20 - - -## Mysql 설치 -링크 - - -## 환경변수 설정 -(적절하게 key, prefix, value 수정해서 넣기!) -_DATABASE_URI = '' -_STAGE = 'PROD' -TOAST_APP_KEY = '' -SMS_SENDER_NO = '' - - -## service 등록 -notion 참고! - -## API - -보안상 보이면 안되는 컬럼은 문서에서도 안 보입니다! - -http://54.180.100.248/ui/ - - - - diff --git a/_posts/2021-07-27-gin-index-and-gist-index.markdown b/_posts/2021-07-27-gin-index-and-gist-index.markdown index 042546c..8ca6038 100644 --- a/_posts/2021-07-27-gin-index-and-gist-index.markdown +++ b/_posts/2021-07-27-gin-index-and-gist-index.markdown @@ -1,63 +1,55 @@ --- layout: single -title: "좋아요에 관한 간단한 고찰" -date: 2021-06-20 11:10:03 +0900 -categories: [Python, Aws] +title: "Gin index 와 Gist index" +date: 2021-07-27 11:10:03 +0900 +categories: [Postgres, index, gin, gist] --- -## 게시글에 '좋아요' -좋아요, 이게 간단해 보이지만 생각보다 엄청 복잡한 기능입니다. -퀄리티 있는 좋아요 기능을 구현하기 위해서는 다음과 같은 문제를 해결해야 합니다. +# Page -* 새로운 '좋아요' 값은 기존 '좋아요' 값에 영향을 받습니다. (new_like = old_like + 1) - 그렇다면 동시성 문제를 해결하기 위해 Lock 을 걸어야 할까? 같은 고민을 하게 되죠. -* 다양한 종류의 테이블에 좋아요를 할 수 있어야 합니다. 요즘 SNS 보면 댓글에도 좋아요, 게시글에도 좋아요 - 별의별 종류의 테이블에 좋아요를 할 수 있죠. 이건 RDBMS 에서 어떻게 모델링을 해야 하는 걸까요? +* Postgres 는 page 라는 자료구조에 데이터를 저장한다. +* page 는 한 개당 8kb 의 고정된 크기를 가지고 있다. +* page 는 하나의 header 와 여러 개의 items 를 가지고 있다. +* 각 item 은 page 를 가리키는 튜플 이다. (value, pointer) +* 이 튜플의 value 는 해당 자식 페이지의 high key 이고, pointer 는 해당 자식 페이지를 가리키는 포인터 +* 각 item 은 offset 을 가지고 있다. (page 내에서의 id 같은 거임 +* 따라서 page number 와 offset 을 알면 item 하나를 특정할 수 있다. +* 이걸 ctid 라고 한다. ctid = (page_number, offset) -* 좋아요는 쓰기보다 읽기가 훨씬 많은 데이터 입니다. 따라서 좋아요 수를 계산하기 위해 record 를 매 번 세는 것은 - 효율적이지 않습니다. 총 좋아요 값을 저장할 필요가 있습니다. -* 운영 측면에서 좋아요 수를 가지고 통계를 내기에 편리해야 합니다. +# B-Tree +Postgres 는 Lehman & Yao Btree 를 구현한다. -## 좋아요를 구현하는 다양한 방법들 - +Btree index 의 첫번째 page 를 metapage 라고 한다. +(B tree 에 insert 를 하다보면 root 가 바뀔 수도 있다. 따라서 metapage 가 항상 같은 자리에 있으면서 새로운 root 를 가리킬 +필요가 있다.) +* root page 의 block number 를 가지고 있다. +* root 의 level 을 가지고 있다. -### 좋아요 테이블이 수많은 테이블과 직접 foreign key 를 맺는 방법 -* likes 가 수많은 foreign key 중 하나만 값을 갖고 나머지는 NULL 일 것을 보장해야 합니다. mysql 만으로는 할 수 없고, - 코드 상에서 제한을 두어야겠죠? +root, parent, leave 는 모두 page 이며 구조도 같다. +* block number 를 가지고 있다. +* high key 를 가지고 있다. (root 제외) +* 이전 페이지와 다음 페이지를 가리키는 pointer 를 가지고 있다. +## High key +Lehman & Yao Btree 구현체에 해당되는 내용임 +page 내의 가장 큰 값을 가진 item 이다. (모든 item 은 high key 와 같거나 보다 작은 value 를 갖는다.) -### Document 에 좋아요를 하는 방법 +왜 b tree 는 full text search 에 부적합하지? 쪼갤 수 없어서? -* 공통된 부모를 두고, 부모에 좋아요를 연결 -* NULL 인 foreign key 가 없습니다. -* 좋아요 수를 구하기 위해서 바로 likes 를 join 할 수 없고, documents 를 중간에 join 해야 합니다. -* documents 에 like_cnt 를 둘 수 있습니다. -## 운영 측면에서 통계 내기 +# Reference -### 좋아요가 가장 많은 게시글은 무엇인가? +https://www.youtube.com/watch?v=2l-nCkPQVuQ -간단한 쿼리로 알아낼 수 있습니다. -```sql -SELECT MAX(id) FROM likes group by article_id; -``` - - - - - - - -### 좋아요 수를 읽어들이지 않고, 바로 UPDATE 를 치는 방법 -Lock 을 걸지 않고 문제를 해결하는 아주 깔끔한 방법입니다. +https://www.youtube.com/watch?v=ncwqtsjlSBE