Skip to content

Commit

Permalink
정리
Browse files Browse the repository at this point in the history
  • Loading branch information
aliwo committed Oct 30, 2022
1 parent 4860c7f commit e970039
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 122 deletions.
117 changes: 117 additions & 0 deletions _drafts/2020-11-22-monad.markdown
Original file line number Diff line number Diff line change
@@ -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 클래스입니다!


66 changes: 66 additions & 0 deletions _drafts/2021-06-20-concerning-like.markdown
Original file line number Diff line number Diff line change
@@ -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 을 걸지 않고 문제를 해결하는 아주 깔끔한 방법입니다.






10 changes: 0 additions & 10 deletions _posts/2020-11-22-monad.markdown

This file was deleted.

16 changes: 0 additions & 16 deletions _posts/2020-12-19-Python Descriptor.markdown

This file was deleted.

8 changes: 0 additions & 8 deletions _posts/2021-01-03-pyenv.markdown

This file was deleted.

50 changes: 0 additions & 50 deletions _posts/2021-06-20-concerning-like.markdown

This file was deleted.

68 changes: 30 additions & 38 deletions _posts/2021-07-27-gin-index-and-gist-index.markdown
Original file line number Diff line number Diff line change
@@ -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



Expand Down

0 comments on commit e970039

Please sign in to comment.