<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>4hyoungsoo_.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Fri, 13 Oct 2023 20:01:50 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. 4hyoungsoo_.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/4hyoungsoo_" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Pyspark 최대 온도 찾기]]></title>
            <link>https://velog.io/@4hyoungsoo_/Pyspark-%EC%B5%9C%EB%8C%80-%EC%98%A8%EB%8F%84-%EC%B0%BE%EA%B8%B0</link>
            <guid>https://velog.io/@4hyoungsoo_/Pyspark-%EC%B5%9C%EB%8C%80-%EC%98%A8%EB%8F%84-%EC%B0%BE%EA%B8%B0</guid>
            <pubDate>Fri, 13 Oct 2023 20:01:50 GMT</pubDate>
            <description><![CDATA[<pre><code class="language-csv"># sample data set
...
ITE00100554,18000101,TMAX,-75,,,E,
ITE00100554,18000101,TMIN,-148,,,E,
GM000010962,18000101,PRCP,0,,,E,
...</code></pre>
<pre><code class="language-python">from pyspark import SparkConf, SparkContext

# spark setting
conf = SparkConf().setMaster(&quot;local&quot;).setAppName(&quot;MinTemperatures&quot;)
sc = SparkContext(conf = conf)


# 텍스트 파일로 읽어들인 RDD를 가공하기 쉽게 (key, value1, value2)로 가공하는 함수
def parseLine(line):
    # csv seperate &#39;,&#39;
    fields = line.split(&#39;,&#39;)
    stationID = fields[0]
    entryType = fields[2]
    # C -&gt; F
    temperature = float(fields[3]) * 0.1 * (9.0 / 5.0) + 32.0
    return (stationID, entryType, temperature)

# csv 파일을 텍스트 RDD로 생성
lines = sc.textFile(&quot;1800.csv&quot;)
# (key, **value)로 변환
parsedLines = lines.map(parseLine)
# 최대 온도를 구하기 위해 TMAX Type만을 필터링
minTemps = parsedLines.filter(lambda x: &quot;TMAX&quot; in x[1])
# 집계 함수를 활용하기 위해 (key, value)형식으로 변환
stationTemps = minTemps.map(lambda x: (x[0], x[2]))
# reduceByKey 집계 함수를 사용하여 key값 별로 최대 값만 남김
minTemps = stationTemps.reduceByKey(lambda x, y: max(x,y))
# 모든 RDD값을 반환
results = minTemps.collect();

for result in results:
    print(result[0] + &quot;\t{:.2f}F&quot;.format(result[1]))
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[PySpark RDD basic]]></title>
            <link>https://velog.io/@4hyoungsoo_/PySpark-RDD-basic</link>
            <guid>https://velog.io/@4hyoungsoo_/PySpark-RDD-basic</guid>
            <pubDate>Thu, 29 Jun 2023 07:40:33 GMT</pubDate>
            <description><![CDATA[<pre><code class="language-python">from pyspark import SparkConf, SparkContext
import collections

conf = SparkConf().setMaster(&quot;local&quot;).setAppName(&quot;RatingsHistogram&quot;)
sc = SparkContext(conf=conf)

lines = sc.textFile(&quot;./ml-100k/u.data&quot;)
ratings = lines.map(lambda x: x.split()[2])
result = ratings.countByValue()

sortedResults = collections.OrderedDict(sorted(result.items()))
for key, value in sortedResults.items():
    print(&quot;%s %i&quot; % (key, value))
</code></pre>
<h2 id="1-sparkconf와-sparkcontext를-생성합니다">1. SparkConf와 SparkContext를 생성합니다.</h2>
<pre><code class="language-python">from pyspark import SparkConf, SparkContext
import collections

conf = SparkConf().setMaster(&quot;local&quot;).setAppName(&quot;RatingsHistogram&quot;)
sc = SparkContext(conf=conf)</code></pre>
<h2 id="2-데이터를-읽어-들입니다">2. 데이터를 읽어 들입니다.</h2>
<pre><code class="language-python">lines = sc.textFile(&quot;./ml-100k/u.data&quot;)</code></pre>
<h2 id="3-평점을-추출합니다">3. 평점을 추출합니다.</h2>
<pre><code class="language-python">ratings = lines.map(lambda x: x.split()[2])</code></pre>
<h2 id="4-평점을-세어-봅니다">4. 평점을 세어 봅니다.</h2>
<pre><code class="language-python">result = ratings.countByValue()</code></pre>
<h2 id="5-결과를-정렬합니다">5. 결과를 정렬합니다.</h2>
<pre><code class="language-python">sortedResults = collections.OrderedDict(sorted(result.items()))</code></pre>
<h2 id="6-결과를-출력합니다">6. 결과를 출력합니다.</h2>
<pre><code class="language-python">for key, value in sortedResults.items():
    print(&quot;%s %i&quot; % (key, value))</code></pre>
<h2 id="결론">결론</h2>
<p>Spark는 RDD를 사용하여 데이터를 처리합니다. RDD는 분산된 데이터 세트이며, Spark는 RDD를 사용하여 병렬로 작업을 수행할 수 있습니다.
```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Resilient Distributed Dataset (RDD)]]></title>
            <link>https://velog.io/@4hyoungsoo_/Resilient-Distributed-Dataset-RDD</link>
            <guid>https://velog.io/@4hyoungsoo_/Resilient-Distributed-Dataset-RDD</guid>
            <pubDate>Wed, 28 Jun 2023 06:16:16 GMT</pubDate>
            <description><![CDATA[<h2 id="spark의-작동-원리">Spark의 작동 원리</h2>
<blockquote>
<p>Spark의 핵심은 Resilient Distributed Dataset (RDD) -&gt; 복구 가능한 분산 데이터 셋</p>
</blockquote>
<h3 id="rdd">RDD</h3>
<ul>
<li><p>다양한 데이터 세트를 추상화 한 것.</p>
<blockquote>
<p>RDD는 분산되고 변형하는 성질을 갖고 있어 여러 클러스터에 나눌 수 있고 개인 컴퓨터에서도 작동 가능. 클러스터의 특정 노드에 이상이 생겨도 자동으로 처리, 노드 하나가 작동을 멈춰도 계속 작동하면서 작업을 재분배.</p>
</blockquote>
</li>
<li><p>RDD는 큰 데이터 셋 -&gt; 한 데이터를 다른 데이터로 변환하는데 쓰임</p>
</li>
</ul>
<h4 id="spark-context---sc">Spark context -&gt; sc</h4>
<p>sc객체를 사용해서 RDD를 생성 할 수 있음.</p>
<h3 id="rdd-변형">RDD 변형</h3>
<ul>
<li><p>map -&gt; 데이터를 불러와 다른 데이터로 변형. 기존 RDD의 모든 엔트리가 새 RDD의 새로운 값으로 변형</p>
<pre><code class="language-python">rdd.map(lamdba x: x**x</code></pre>
</li>
<li><p>flatmap -&gt; map과 비슷한 기능을 수행, 단 새로 생성된 RDD가 기존 RDD보다 크거나 작을 수 있음.</p>
</li>
<li><p>filter -&gt; RDD에 있는 데이터에서 일부분만 보고 싶을 때 사용</p>
</li>
<li><p>distinct -&gt; RDD에서 중복값 제거 함수</p>
</li>
<li><p>uninon, intersaction, subtract -&gt; RDBMS와 동일</p>
</li>
</ul>
<h3 id="rdd-집계">RDD 집계</h3>
<ul>
<li><p>collect -&gt; 원하는 값만 출력</p>
</li>
<li><p>countByValue -&gt; 특정한 값이 얼마나 나왔는가</p>
</li>
<li><p>take, top -&gt; 최종적으로 완성한 RDD에서 일부 값을 가져온다</p>
</li>
<li><p><strong>reduce</strong> -&gt; 모든 값에 특정한 연산을 해서 하나의 RDD로 합쳐준다</p>
</li>
</ul>
<h3 id="유향-비순환-그래프">유향 비순환 그래프</h3>
<blockquote>
<p>Spark가 빠른이유. Spark에 액션을 입력하면 바로 유향 비순환 그래프를 생성하여 원하는 값을 얻으려면어떻게 해야하는지 최적화된 방법을 계산.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Pig]]></title>
            <link>https://velog.io/@4hyoungsoo_/Pig</link>
            <guid>https://velog.io/@4hyoungsoo_/Pig</guid>
            <pubDate>Wed, 28 Jun 2023 05:36:30 GMT</pubDate>
            <description><![CDATA[<h2 id="pig">Pig</h2>
<p>Pig를 사용하면 더 쉽게 데이터를 처리할 수 있다.</p>
<blockquote>
<p>Hadoop과 MapReduce 위에 구축되었기 때문에 이를 통해 매퍼와 리듀서를 작성하지 않고 MapReduce 작업을 할 수 있다.</p>
</blockquote>
<ul>
<li>Apache Pig-&gt; 매퍼나 리듀서를 작성하지 않고 데이터를 빠르게 분석할 수 있는 방법</li>
</ul>
<h3 id="mapreduce-개발-사이클-타임">MapReduce 개발 사이클 타임</h3>
<p>MapReduce의 가장 큰 문제는 개발 사이클 타임</p>
<p>MapReduce 프로그램을 개발해 실행하고 원하는 작업을 수행하기까지 오랜 시간이 걸린다.</p>
<blockquote>
<p>그래서 Pig가 등장</p>
</blockquote>
<p>Pig는 MapReduce 위에서 작동하고 Pig Latin이라는 새 프로그래밍 언어를 사용 -&gt; SQL과 비슷하다.</p>
<p>다른 점은 Pig는 절차형 언어라는 겁니다 아주 간단한 스크립트 양식을 사용해 단계별로 데이터 간에 여러 관계를 설정. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[MapReduce 분산 처리 방법]]></title>
            <link>https://velog.io/@4hyoungsoo_/MapReduce-%EB%B6%84%EC%82%B0-%EC%B2%98%EB%A6%AC-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@4hyoungsoo_/MapReduce-%EB%B6%84%EC%82%B0-%EC%B2%98%EB%A6%AC-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Wed, 28 Jun 2023 05:29:46 GMT</pubDate>
            <description><![CDATA[<ul>
<li>매퍼가 키-값 쌍을 추출</li>
<li>셔플과 정렬은 각 고유 키와 연관된 값을 구조화</li>
<li>리듀서는 구조화된 정보를 전달받아 최종 출력물을 생산</li>
</ul>
<h2 id="mapreducer-in-hadoop">MapReducer in Hadoop</h2>
<p>정말 큰 데이터 세트를 가진 클러스터를 운영하고 있다고 가정하면, 처리 과정을 여러 컴퓨터에 배분하거나 적어도 여러 작업(task)에 걸쳐 진행해야만 한다.</p>
<blockquote>
<p>같은 컴퓨터 안에서 다른 프로세스나 컨테이너를 실행할 수도 있다는 것. 혹은 컴퓨터 여러 대에 걸쳐 분배했을 수도 있다
예를들어 3개의 노드에 나눠 매핑한다고 가정한다면, 데이터를 가져오며 세 부분으로 나눠 각각의 노드에 분배함</p>
</blockquote>
<h3 id="분산처리가-가능한-이유">분산처리가 가능한 이유</h3>
<ul>
<li>매핑 단계에서는 다른 노드 있는 줄을 신경쓰지 않아도 됨으로 작업을 병렬화하기에 수월.</li>
<li>입력 데이터 한 덩어리를 한 컴퓨터에서 매핑하고 다른 덩어리는 또 다른 컴퓨터에서 동시에 매핑한다면 Hadoop은 이 작업이 끝나면 정보를 받아오기만 하면 됨.</li>
</ul>
<h3 id="셔플과-정렬-과정에서-분산처리는">셔플과 정렬 과정에서 분산처리는?</h3>
<p>셔플과 정렬 과정을 여러 노드로 나눠 작업을 하게 된다면, 다른 노드에서 같은 키 값이 나올 수도 있다. 이를 같은 키끼리 모아 리듀서로 보내야하는데 어떻게 하는걸까</p>
<blockquote>
<p>예를 들어 ID=1의 사용자의 값이 두 노드에 걸쳐있고 셔플과 정렬 작업에서 이 둘은 함께 집계되게 되는데 MapReduce가 이 작업을 대신 수행한다. 네트워크를 활용하여 여러 노드들간 데이터를 보내는 방식을 사용하지 않음. 대신 이 모든 데이터를 merge sort하게 된다.</p>
</blockquote>
<p>즉 각각의 노드에서 맵퍼를 통해 키-값 구조로 구조화 시킨 후 합병 정렬을 통해 셔츨과 정렬 과정을 수행한다.</p>
<h2 id="mapreducer-architecture">MapReducer Architecture</h2>
<p><img src="https://velog.velcdn.com/images/4hyoungsoo_/post/86431a34-020f-4f5f-b5f3-77c067091a98/image.png" alt=""></p>
<ul>
<li>클라이언트 노드가 작업을 개시 -&gt; MapReduce 작업을 지시합</li>
<li>클라이언트는 먼저 YARN(job)과 소통 -&gt; 어떤 MapReduce 작업이 필요한지<blockquote>
<p>YARN -&gt; 리소스 교섭자, 어떤 머신에서 무엇을 실행할지 관리.  클러스터의 어떤 머신이 가용하고 어떤 머신의 성능은 얼마인지 등의 정보를 기억</p>
</blockquote>
</li>
<li>데이터를 HDFS나 적절한 분산 파일 시스템에 복사합니다</li>
<li>&#39;MapReduce Master&#39;<blockquote>
<p>MapReduce Master는 개별 매핑과 리듀싱 작업을 주시하고 리소스 관리자와 협업해 작업을 클러스터에 걸쳐 배분합니다</p>
</blockquote>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[MapReduce 정의 및 작동방식]]></title>
            <link>https://velog.io/@4hyoungsoo_/MapReduce-%EC%A0%95%EC%9D%98-%EB%B0%8F-%EC%9E%91%EB%8F%99%EB%B0%A9%EC%8B%9D</link>
            <guid>https://velog.io/@4hyoungsoo_/MapReduce-%EC%A0%95%EC%9D%98-%EB%B0%8F-%EC%9E%91%EB%8F%99%EB%B0%A9%EC%8B%9D</guid>
            <pubDate>Wed, 28 Jun 2023 05:06:47 GMT</pubDate>
            <description><![CDATA[<h1 id="mapreduce">MapReduce</h1>
<p>MapReduce는 HDFS, YARN과 함께 제공되는 Hadoop의 핵심 기술.</p>
<ul>
<li>Hadoop에 내재된 기능이며 클러스터에 데이터의 처리를 분배.</li>
<li>MapReduce는 데이터를 파티션으로 나눠서 클러스터에 걸쳐 병렬 처리되도록 한다</li>
</ul>
<h2 id="data-mapper">Data Mapper</h2>
<p>매핑은 기본적으로 데이터를 변형시킨다
즉 데이터가 한 줄씩 들어오면 매퍼는 그 데이터를 변형시킨다.</p>
<ul>
<li>키-값 쌍으로 전환</li>
</ul>
<blockquote>
<p>예를 들어 각 사용자가 시청한 영화의 수를 집계하려고 한다면, 키는 사용자의 ID, 값은 사용자가 평가한 영화가 될 것. 일반적인 python dict 자료구조와는 달리 중복된 키가 존재할 수 있음.
이 경우 ID=1의 사용자가 두개 이상의 영화를 평가한 것.
맵핑 단계에서 같은 키값이 나오는 것은 전혀 문제될 것이 없음.</p>
</blockquote>
<p>들어오는 데이터에서 필요한 정보를 추출하고 이해할 수 있는 구조로 정리.
모든 입력 줄(input line)마다 매퍼는 중요한 데이터를 추출하고 구조화해한 줄을 출력한다.</p>
<h2 id="셔플과-정렬">&#39;셔플과 정렬&#39;</h2>
<blockquote>
<p>&#39;셔플과 정렬&#39; 단계에서 일어나는 일은 각각의 키-값 쌍을 읽어서 고유 키에 짝 지어진 값을 집계. 간단하게 여러개의 중복된 키가 존재한다면 이를 하나로 묶어줌.</p>
</blockquote>
<h2 id="date-reducer">Date Reducer</h2>
<p>Reducer의 역할은 데이터를 집계하는 것.</p>
<h3 id="정리">정리</h3>
<ul>
<li><p>매퍼는 각 줄을 키-값 쌍으로 변형</p>
</li>
<li><p>&#39;셔플과 정렬&#39;은 각 데이터를 집계해 정렬</p>
</li>
<li><p>리듀서는 이 데이터를 원하는 대로 처리할 수 있죠</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[django annotate에 filter 적용하기]]></title>
            <link>https://velog.io/@4hyoungsoo_/django-annotate%EC%97%90-filter-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@4hyoungsoo_/django-annotate%EC%97%90-filter-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 09 Mar 2023 07:12:57 GMT</pubDate>
            <description><![CDATA[<p><a href="https://velog.io/@4hyoungsoo_/django-orm%EC%9C%BC%EB%A1%9C-lichess-%EB%B6%84%EC%84%9D-%EB%94%B0%EB%9D%BC%EC%9E%A1%EA%B8%B0">lichess 분석 기능 따라잡기</a></p>
<p>이전에 포스팅했던 새로운 방식으로 코드를 변경했다.</p>
<pre><code class="language-python">@api.get(&#39;/moveline&#39;)
def get_moveline(request, moves: str = None):
    board = chess.Board()
    if moves == None:
        data = list(ChessNotation.objects.annotate(submoves=Substr(&#39;mainline&#39;, 1, 4)).exclude(mainline=&#39;&#39;).values(&#39;submoves&#39;).annotate(cnt=Count(&#39;submoves&#39;), white_win=Count(
            &#39;result&#39;, filter=Q(result__iexact=&#39;white&#39;)), draw=Count(&#39;result&#39;, filter=Q(result__iexact=&#39;draw&#39;)), black_win=Count(&#39;result&#39;, filter=Q(result__iexact=&#39;black&#39;))).order_by(&#39;-cnt&#39;))

        return JsonResponse(data, safe=False)
    else:
        move = moves.split(&#39;,&#39;)
        data = list(ChessNotation.objects.filter(mainline__startswith=moves).exclude(mainline=moves).annotate(submoves=Substr(
            &#39;mainline&#39;, 1+5*len(move), 4)).values(&#39;submoves&#39;).annotate(cnt=Count(&#39;submoves&#39;), white_win=Count(
                &#39;result&#39;, filter=Q(result__iexact=&#39;white&#39;)), draw=Count(&#39;result&#39;, filter=Q(result__iexact=&#39;draw&#39;)), black_win=Count(&#39;result&#39;, filter=Q(result__iexact=&#39;black&#39;))).order_by(&#39;-cnt&#39;))
        return JsonResponse(data, safe=False)</code></pre>
<p>orm이 기존에비해 많이 길어지긴 했지만, 속도측면이나 데이터베이스 용량측면에서 보다 나아졌다고 확신한다.</p>
<h3 id="다중-annotate-조건">다중 annotate 조건</h3>
<p>django annotate를 사용할때 조건을 적용할 수 있다.</p>
<pre><code class="language-python">ChessNotation.objects.filter(mainline__startswith=moves).exclude(mainline=moves).annotate(submoves=Substr(
            &#39;mainline&#39;, 1+5*len(move), 4)).values(&#39;submoves&#39;).annotate(cnt=Count(&#39;submoves&#39;), white_win=Count(
                &#39;result&#39;, filter=Q(result__iexact=&#39;white&#39;)), draw=Count(&#39;result&#39;, filter=Q(result__iexact=&#39;draw&#39;)), black_win=Count(&#39;result&#39;, filter=Q(result__iexact=&#39;black&#39;))).order_by(&#39;-cnt&#39;))</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[체스 프로젝트 구축 요구사항]]></title>
            <link>https://velog.io/@4hyoungsoo_/%EC%B2%B4%EC%8A%A4-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B5%AC%EC%B6%95-%EC%9A%94%EA%B5%AC%EC%82%AC%ED%95%AD</link>
            <guid>https://velog.io/@4hyoungsoo_/%EC%B2%B4%EC%8A%A4-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B5%AC%EC%B6%95-%EC%9A%94%EA%B5%AC%EC%82%AC%ED%95%AD</guid>
            <pubDate>Thu, 09 Mar 2023 04:09:48 GMT</pubDate>
            <description><![CDATA[<p><a href="https://github.com/HyoungSooo/docker-chess">나만의 체스 분석, 연습 프로젝트</a></p>
<p>프로젝트를 진행하면서 생각나는대로 즉흥적으로 api설계를 하고 모델들을 정의하다보니 전반적으로 진행이 매끄럽지 않은듯한 느낌이 들었다.</p>
<p>이미 진행했던 프로젝트를 리팩토링 하는 겸 요구사항을 명확하게 정의하여 보다 깔끔한 코드를 작성하기 위해 요구사항을 정리해보려한다.</p>
<h3 id="요구사항">요구사항</h3>
<ul>
<li><p><input disabled="" type="checkbox">  lichess database에서 제공하는 pgn파일을 처리할 수 있는 데이터 파이프라인 구축</p>
</li>
<li><p><input checked="" disabled="" type="checkbox">  체스 분석 기능</p>
<ul>
<li>체스 시작 포지션 부터 실제 게임에서 나온 수들을 카운트해서 보여줄 수 있어야함.</li>
<li>stockfish를 활용하여 특정 포지션에서의 최선의 수를 찾는다.<ul>
<li>stockfish를 활용하여 현재 포지션의 유불리를 판단.</li>
<li>레이팅에 따른 다른 수들을 보여줘야함. (1800~2000 의 수들만 보여준다든가)</li>
</ul>
</li>
</ul>
</li>
<li><p><input disabled="" type="checkbox">  체스 퍼즐</p>
<ul>
<li>체스 퍼즐을 테마에 따라 분류하는 기능<ul>
<li>체스 퍼즐을 풀면서 실제로 수를 움직이기전에 미리둬보는 기능</li>
</ul>
</li>
</ul>
</li>
<li><p><input disabled="" type="checkbox">  stockfish와 배틀</p>
<ul>
<li>stockfish의 난이도를 직접 설정할 수 있어야함.</li>
</ul>
</li>
<li><p><input disabled="" type="checkbox">  Dashboard</p>
<ul>
<li>lichess database에서 가져온 데이터를 활용하여 여러가지 분석된 결과를 제공해야함 (특정 레이팅에서 가장 승률이 높은 오프닝, 가장 많이 사용된 오프닝, 첫수에 따른 오프닝 선택, 전체 오프닝의 승률 ..etc)</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[django orm으로 lichess 분석 따라잡기]]></title>
            <link>https://velog.io/@4hyoungsoo_/django-orm%EC%9C%BC%EB%A1%9C-lichess-%EB%B6%84%EC%84%9D-%EB%94%B0%EB%9D%BC%EC%9E%A1%EA%B8%B0</link>
            <guid>https://velog.io/@4hyoungsoo_/django-orm%EC%9C%BC%EB%A1%9C-lichess-%EB%B6%84%EC%84%9D-%EB%94%B0%EB%9D%BC%EC%9E%A1%EA%B8%B0</guid>
            <pubDate>Thu, 09 Mar 2023 02:42:11 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>lichess database에서 추출한 74만개의 체스 기보 데이터를 가지고 lichess나 chess.com에서 제공하는 analze기능을 따라잡아보자</p>
</blockquote>
<p>체스는 전략과 계획이 필요한 대표적인 보드 게임. 체스에서 성공하기 위해서는 다양한 기술과 전략을 학습하고 연습해야 한다. 실력을 향상시키기 위해서는 자신의 게임을 분석하고, 상대방의 전략을 이해하는 것이 매우 중요하다.</p>
<p>lichess나 chess.com과 같은 사이트들에서 여러가지 퍼즐이나 여러가지 상황에 따른 다음 수들을 실제 행해졌던 게임들에서 수집하여 보여주는 기능들이 있고, 여러가지 체스 오프닝들이나, 전략을 공부할 수 있는 퍼즐과 같은 기능들을 제공한다.</p>
<p>평소 체스에 관심이 많았던 사람으로써, 개인 프로젝트로 lichess나 chess.com사이트의 기능들을 클론하고, 내가 학습하기 용이한 기능들을 추가하여, 개인적인 체스 분석, 연습 사이트를 만드는 프로젝트를 진행하고 있다.</p>
<p><a href="https://github.com/HyoungSooo/docker-chess">나만의 체스 분석 프로그램을 만들어보자 프로젝트</a></p>
<p>이번 포스팅은 lichess 분석기능에 대해서 정리한다.</p>
<h3 id="기존-방법">기존 방법</h3>
<p>기존의 방법은 lichess database에서 제공하는 pgn파일들을 가져와 데이터를 수집하고 정제하여 데이터베이스에 적재하는 파이프라인을 구축하였다.</p>
<p>파이프라인 코드 예시</p>
<pre><code class="language-python">
class Processor:

    def __init__(self, fpath, num, checkpoint, is_start=False) -&gt; None:
        self.df = pd.DataFrame()
        self.num = num
        self.msg = &#39;done&#39;
        self.fpath = fpath
        self.checkpoint = checkpoint
        self.status = False
        self.next_checkpoint = checkpoint + num
        self.is_start = False

        b, m = self.parse_data_to_csv()
        if b:
            self.msg = self.store_data()
        else:
            self.msg = m

    def parse_data_to_csv(self):
        pgn = open(self.fpath, &#39;r&#39;)
        if self.is_start:
            for _ in range(1):
                game = chess.pgn.read_game(pgn)

        for i in range(self.checkpoint):
            game = chess.pgn.read_game(pgn)

        game = chess.pgn.read_game(pgn)
        num = 0
        if game:
            while game != None:
                if num == self.num:
                    break
                if not self.df.empty:
                    df = pd.DataFrame(
                        list(game.headers.values()) + [self.san_to_uci(game.mainline_moves())]).T
                    df.columns = list(game.headers.keys()) + [&#39;mainline&#39;]
                    self.df = pd.concat([self.df, df], ignore_index=True)
                else:
                    self.df = pd.DataFrame(
                        list(game.headers.values()) + [self.san_to_uci(game.mainline_moves())]).T
                    self.df.columns = list(game.headers.keys()) + [&#39;mainline&#39;]

                num += 1
                game = chess.pgn.read_game(pgn)

            if game == None:
                self.status = True
                self.df.drop(self.df.index[-1])

            return True, &#39;done&#39;
        else:
            return False, f&#39;{self.fpath} is already done.&#39;

            .......</code></pre>
<p>lichess database에서 제공하는 파일들은 기본적으로 크기가 매우 크기 때문에 파일을 분산하여 처리하는 api를 만들어 데이터베이스에 저장했다.</p>
<p>여기서 저장한 데이터를 활용하여, 체스의 id라고 할 수 있는 fen을 활용하여 각각의 fen마다 사람들이 둔 수들을 하나씩 세서 데이터베이스에 저장했다.</p>
<pre><code class="language-python">@api.get(&#39;/mainline&#39;)
def parse_mainline(request, num: int):
    pool = Pool(2)
    first_pk = ChessNotation.objects.first()
    try:
        checkpoint = ChessMainline.objects.all()[0]
        if checkpoint.checkpoint &lt; first_pk.pk:
            checkpoint.checkpoint = first_pk.pk
    except:
        checkpoint = ChessMainline.objects.create(checkpoint=first_pk.pk)
    data = ChessNotation.objects.filter(
        pk__gte=checkpoint.checkpoint, pk__lt=checkpoint.checkpoint + num)

    checkpoint.checkpoint += num

    checkpoint.save()
    if data:
        # MainlineProcessor(data)

        pool.map(MainlineProcessor, data)

    return
</code></pre>
<pre><code class="language-python">class MainlineProcessor:
    def __init__(self, data: ChessNotation) -&gt; None:
        self.data = data
        self.df = pd.DataFrame()
        self.current = None

        self.parse()

    def process(self, next_move, result, fen):
        try:
            start = ChessProcess.objects.get(fen=fen)
        except:
            try:
                start = ChessProcess.objects.create(fen=fen)
            except:
                return
        try:
            created_move = start.next_moves.get(next_move=next_move)
        except:
            created_move = ChessFenNextMoves.objects.create(
                fen=start, white=0, draw=0, black=0, next_move=next_move, cnt=0)

        created_move.cnt += 1
        if result == &#39;white&#39;:
            created_move.white += 1
        elif result == &#39;black&#39;:
            created_move.black += 1
        else:
            created_move.draw += 1

        created_move.save()

    def parse(self):
        i = self.data
        # for i in self.data:
        board = chess.Board()
        moves = i.mainline.split(&#39;,&#39;)

        self.process(moves[0], i.result, board.fen())

        for cnt in range(len(moves) - 1):
            board.push_uci(moves[cnt])
            fen = board.fen()

            self.process(moves[cnt+1], i.result, fen)
</code></pre>
<p>python의 내장 라이브러리인 multiprocessing을 활용했음에도 불구하고 100개의 데이터를 정제하는데 대략 30초의 시간이 소요됐고, 각각의 fen을 따로 데이터베이스에 저장함에 따라 100000개의 기보를 정제하는데 3000000만개의 fen 데이터가 생성되는 아주 비효율적인 방법을 사용하였다.</p>
<h3 id="수정된-방법">수정된 방법</h3>
<p>수정된 방법은 아주 간단하고 빠르다. django orm기능을 적극 활용한다.</p>
<pre><code class="language-python">import chess

board = chess.Board()
legal_moves = list(board.legal_moves)

for move in legal_moves:
    print(&lt;database model name&gt;.objects.filter(mainline__startswith = move).count(), move)</code></pre>
<table>
<thead>
<tr>
<th>count</th>
<th>move</th>
</tr>
</thead>
<tbody><tr>
<td>141</td>
<td>g1h3</td>
</tr>
<tr>
<td>21899</td>
<td>g1f3</td>
</tr>
<tr>
<td>3799</td>
<td>b1c3</td>
</tr>
<tr>
<td>60</td>
<td>b1a3</td>
</tr>
<tr>
<td>610</td>
<td>h2h3</td>
</tr>
<tr>
<td>13416</td>
<td>g2g3</td>
</tr>
<tr>
<td>907</td>
<td>f2f3</td>
</tr>
<tr>
<td>19884</td>
<td>e2e3</td>
</tr>
<tr>
<td>6709</td>
<td>d2d3</td>
</tr>
<tr>
<td>1927</td>
<td>c2c3</td>
</tr>
<tr>
<td>10138</td>
<td>b2b3</td>
</tr>
<tr>
<td>884</td>
<td>a2a3</td>
</tr>
<tr>
<td>798</td>
<td>h2h4</td>
</tr>
<tr>
<td>2894</td>
<td>g2g4</td>
</tr>
<tr>
<td>7503</td>
<td>f2f4</td>
</tr>
<tr>
<td>427490</td>
<td>e2e4</td>
</tr>
<tr>
<td>181418</td>
<td>d2d4</td>
</tr>
<tr>
<td>23802</td>
<td>c2c4</td>
</tr>
<tr>
<td>4474</td>
<td>b2b4</td>
</tr>
<tr>
<td>737</td>
<td>a2a4</td>
</tr>
</tbody></table>
<p>정말 간단하다..
머리가 나쁘면 몸이 고생한다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[체스 레이팅 별 가장 높은 승률 오프닝]]></title>
            <link>https://velog.io/@4hyoungsoo_/%EC%B2%B4%EC%8A%A4-%EB%A0%88%EC%9D%B4%ED%8C%85-%EB%B3%84-%EA%B0%80%EC%9E%A5-%EB%86%92%EC%9D%80-%EC%8A%B9%EB%A5%A0-%EC%98%A4%ED%94%84%EB%8B%9D</link>
            <guid>https://velog.io/@4hyoungsoo_/%EC%B2%B4%EC%8A%A4-%EB%A0%88%EC%9D%B4%ED%8C%85-%EB%B3%84-%EA%B0%80%EC%9E%A5-%EB%86%92%EC%9D%80-%EC%8A%B9%EB%A5%A0-%EC%98%A4%ED%94%84%EB%8B%9D</guid>
            <pubDate>Fri, 03 Mar 2023 09:23:32 GMT</pubDate>
            <description><![CDATA[<p>lichess database를 활용해서 각 레이팅별 가장 높은 승률의 오프닝, 가장 승률이 낮은 오프닝을 알아보자.</p>
<p>lichess database 기준 대략 74만개의 게임을 분석.</p>
<p><img src="https://velog.velcdn.com/images/4hyoungsoo_/post/f3ea0ab8-3fc5-44eb-b992-bb6147b95fd9/image.png" alt=""></p>
<blockquote>
<p>하위 레이팅 1200 ~ 1800, 중위 레이팅 1900 ~ 2400, 상위 레이팅 2500~ 로 설정하고 각 레이팅 별로 어떤 오프닝이 가장 인기있는지 알아보자.</p>
</blockquote>
<h3 id="하위-레이팅">하위 레이팅</h3>
<p>most_count</p>
<table>
<thead>
<tr>
<th align="left"></th>
<th align="right">white</th>
<th align="right">draw</th>
<th align="right">black</th>
<th align="right">count</th>
</tr>
</thead>
<tbody><tr>
<td align="left">Van&#39;t Kruijs Opening</td>
<td align="right">909</td>
<td align="right">40</td>
<td align="right">737</td>
<td align="right">1686</td>
</tr>
<tr>
<td align="left">Scandinavian Defense</td>
<td align="right">607</td>
<td align="right">42</td>
<td align="right">583</td>
<td align="right">1232</td>
</tr>
<tr>
<td align="left">Scandinavian Defense: Mieses-Kotroc Variation</td>
<td align="right">705</td>
<td align="right">25</td>
<td align="right">275</td>
<td align="right">1005</td>
</tr>
<tr>
<td align="left">King&#39;s Pawn Game: Wayward Queen Attack</td>
<td align="right">592</td>
<td align="right">22</td>
<td align="right">378</td>
<td align="right">992</td>
</tr>
<tr>
<td align="left">Queen&#39;s Pawn Game: Chigorin Variation</td>
<td align="right">471</td>
<td align="right">33</td>
<td align="right">359</td>
<td align="right">863</td>
</tr>
<tr>
<td align="left">Horwitz Defense</td>
<td align="right">440</td>
<td align="right">23</td>
<td align="right">287</td>
<td align="right">750</td>
</tr>
<tr>
<td align="left">Bishop&#39;s Opening</td>
<td align="right">411</td>
<td align="right">12</td>
<td align="right">226</td>
<td align="right">649</td>
</tr>
<tr>
<td align="left">Queen&#39;s Pawn Game #2</td>
<td align="right">361</td>
<td align="right">20</td>
<td align="right">266</td>
<td align="right">647</td>
</tr>
<tr>
<td align="left">Philidor Defense #2</td>
<td align="right">371</td>
<td align="right">26</td>
<td align="right">247</td>
<td align="right">644</td>
</tr>
<tr>
<td align="left">King&#39;s Pawn Game: Leonardis Variation</td>
<td align="right">326</td>
<td align="right">21</td>
<td align="right">283</td>
<td align="right">630</td>
</tr>
</tbody></table>
<p>most_win_white</p>
<table>
<thead>
<tr>
<th align="left"></th>
<th align="right">white</th>
<th align="right">draw</th>
<th align="right">black</th>
<th align="right">count</th>
<th align="right">white_rate</th>
<th align="right">draw_rate</th>
<th align="right">black_rate</th>
</tr>
</thead>
<tbody><tr>
<td align="left">Scandinavian Defense: Mieses-Kotroc Variation</td>
<td align="right">705</td>
<td align="right">25</td>
<td align="right">275</td>
<td align="right">1005</td>
<td align="right">0.701493</td>
<td align="right">0.0248756</td>
<td align="right">0.273632</td>
</tr>
<tr>
<td align="left">Philidor Defense #3</td>
<td align="right">386</td>
<td align="right">12</td>
<td align="right">162</td>
<td align="right">560</td>
<td align="right">0.689286</td>
<td align="right">0.0214286</td>
<td align="right">0.289286</td>
</tr>
<tr>
<td align="left">Scotch Game</td>
<td align="right">393</td>
<td align="right">19</td>
<td align="right">203</td>
<td align="right">615</td>
<td align="right">0.639024</td>
<td align="right">0.0308943</td>
<td align="right">0.330081</td>
</tr>
<tr>
<td align="left">Bishop&#39;s Opening</td>
<td align="right">411</td>
<td align="right">12</td>
<td align="right">226</td>
<td align="right">649</td>
<td align="right">0.633282</td>
<td align="right">0.01849</td>
<td align="right">0.348228</td>
</tr>
<tr>
<td align="left">Modern Defense</td>
<td align="right">321</td>
<td align="right">16</td>
<td align="right">175</td>
<td align="right">512</td>
<td align="right">0.626953</td>
<td align="right">0.03125</td>
<td align="right">0.341797</td>
</tr>
<tr>
<td align="left">King&#39;s Pawn Game: Wayward Queen Attack</td>
<td align="right">592</td>
<td align="right">22</td>
<td align="right">378</td>
<td align="right">992</td>
<td align="right">0.596774</td>
<td align="right">0.0221774</td>
<td align="right">0.381048</td>
</tr>
<tr>
<td align="left">French Defense: Knight Variation</td>
<td align="right">311</td>
<td align="right">16</td>
<td align="right">203</td>
<td align="right">530</td>
<td align="right">0.586792</td>
<td align="right">0.0301887</td>
<td align="right">0.383019</td>
</tr>
<tr>
<td align="left">Horwitz Defense</td>
<td align="right">440</td>
<td align="right">23</td>
<td align="right">287</td>
<td align="right">750</td>
<td align="right">0.586667</td>
<td align="right">0.0306667</td>
<td align="right">0.382667</td>
</tr>
<tr>
<td align="left">Philidor Defense #2</td>
<td align="right">371</td>
<td align="right">26</td>
<td align="right">247</td>
<td align="right">644</td>
<td align="right">0.576087</td>
<td align="right">0.0403727</td>
<td align="right">0.38354</td>
</tr>
<tr>
<td align="left">Queen&#39;s Pawn Game #2</td>
<td align="right">361</td>
<td align="right">20</td>
<td align="right">266</td>
<td align="right">647</td>
<td align="right">0.55796</td>
<td align="right">0.0309119</td>
<td align="right">0.411128</td>
</tr>
</tbody></table>
<p>most_draw</p>
<table>
<thead>
<tr>
<th align="left"></th>
<th align="right">white</th>
<th align="right">draw</th>
<th align="right">black</th>
<th align="right">count</th>
<th align="right">white_rate</th>
<th align="right">draw_rate</th>
<th align="right">black_rate</th>
</tr>
</thead>
<tbody><tr>
<td align="left">Philidor Defense #2</td>
<td align="right">371</td>
<td align="right">26</td>
<td align="right">247</td>
<td align="right">644</td>
<td align="right">0.576087</td>
<td align="right">0.0403727</td>
<td align="right">0.38354</td>
</tr>
<tr>
<td align="left">Queen&#39;s Pawn Game: Chigorin Variation</td>
<td align="right">471</td>
<td align="right">33</td>
<td align="right">359</td>
<td align="right">863</td>
<td align="right">0.545771</td>
<td align="right">0.0382387</td>
<td align="right">0.415991</td>
</tr>
<tr>
<td align="left">Scandinavian Defense</td>
<td align="right">607</td>
<td align="right">42</td>
<td align="right">583</td>
<td align="right">1232</td>
<td align="right">0.492695</td>
<td align="right">0.0340909</td>
<td align="right">0.473214</td>
</tr>
<tr>
<td align="left">King&#39;s Pawn Game: Leonardis Variation</td>
<td align="right">326</td>
<td align="right">21</td>
<td align="right">283</td>
<td align="right">630</td>
<td align="right">0.51746</td>
<td align="right">0.0333333</td>
<td align="right">0.449206</td>
</tr>
<tr>
<td align="left">Modern Defense</td>
<td align="right">321</td>
<td align="right">16</td>
<td align="right">175</td>
<td align="right">512</td>
<td align="right">0.626953</td>
<td align="right">0.03125</td>
<td align="right">0.341797</td>
</tr>
<tr>
<td align="left">Queen&#39;s Pawn Game #2</td>
<td align="right">361</td>
<td align="right">20</td>
<td align="right">266</td>
<td align="right">647</td>
<td align="right">0.55796</td>
<td align="right">0.0309119</td>
<td align="right">0.411128</td>
</tr>
<tr>
<td align="left">Scotch Game</td>
<td align="right">393</td>
<td align="right">19</td>
<td align="right">203</td>
<td align="right">615</td>
<td align="right">0.639024</td>
<td align="right">0.0308943</td>
<td align="right">0.330081</td>
</tr>
<tr>
<td align="left">Horwitz Defense</td>
<td align="right">440</td>
<td align="right">23</td>
<td align="right">287</td>
<td align="right">750</td>
<td align="right">0.586667</td>
<td align="right">0.0306667</td>
<td align="right">0.382667</td>
</tr>
<tr>
<td align="left">French Defense: Knight Variation</td>
<td align="right">311</td>
<td align="right">16</td>
<td align="right">203</td>
<td align="right">530</td>
<td align="right">0.586792</td>
<td align="right">0.0301887</td>
<td align="right">0.383019</td>
</tr>
<tr>
<td align="left">Sicilian Defense</td>
<td align="right">253</td>
<td align="right">14</td>
<td align="right">264</td>
<td align="right">531</td>
<td align="right">0.47646</td>
<td align="right">0.0263653</td>
<td align="right">0.497175</td>
</tr>
</tbody></table>
<p>most_win_black</p>
<table>
<thead>
<tr>
<th align="left"></th>
<th align="right">white</th>
<th align="right">draw</th>
<th align="right">black</th>
<th align="right">count</th>
<th align="right">white_rate</th>
<th align="right">draw_rate</th>
<th align="right">black_rate</th>
</tr>
</thead>
<tbody><tr>
<td align="left">Sicilian Defense</td>
<td align="right">253</td>
<td align="right">14</td>
<td align="right">264</td>
<td align="right">531</td>
<td align="right">0.47646</td>
<td align="right">0.0263653</td>
<td align="right">0.497175</td>
</tr>
<tr>
<td align="left">Scandinavian Defense</td>
<td align="right">607</td>
<td align="right">42</td>
<td align="right">583</td>
<td align="right">1232</td>
<td align="right">0.492695</td>
<td align="right">0.0340909</td>
<td align="right">0.473214</td>
</tr>
<tr>
<td align="left">King&#39;s Pawn Game: Leonardis Variation</td>
<td align="right">326</td>
<td align="right">21</td>
<td align="right">283</td>
<td align="right">630</td>
<td align="right">0.51746</td>
<td align="right">0.0333333</td>
<td align="right">0.449206</td>
</tr>
<tr>
<td align="left">Van&#39;t Kruijs Opening</td>
<td align="right">909</td>
<td align="right">40</td>
<td align="right">737</td>
<td align="right">1686</td>
<td align="right">0.539146</td>
<td align="right">0.0237248</td>
<td align="right">0.437129</td>
</tr>
<tr>
<td align="left">Queen&#39;s Pawn Game: Chigorin Variation</td>
<td align="right">471</td>
<td align="right">33</td>
<td align="right">359</td>
<td align="right">863</td>
<td align="right">0.545771</td>
<td align="right">0.0382387</td>
<td align="right">0.415991</td>
</tr>
<tr>
<td align="left">Queen&#39;s Pawn Game #2</td>
<td align="right">361</td>
<td align="right">20</td>
<td align="right">266</td>
<td align="right">647</td>
<td align="right">0.55796</td>
<td align="right">0.0309119</td>
<td align="right">0.411128</td>
</tr>
<tr>
<td align="left">Philidor Defense #2</td>
<td align="right">371</td>
<td align="right">26</td>
<td align="right">247</td>
<td align="right">644</td>
<td align="right">0.576087</td>
<td align="right">0.0403727</td>
<td align="right">0.38354</td>
</tr>
<tr>
<td align="left">French Defense: Knight Variation</td>
<td align="right">311</td>
<td align="right">16</td>
<td align="right">203</td>
<td align="right">530</td>
<td align="right">0.586792</td>
<td align="right">0.0301887</td>
<td align="right">0.383019</td>
</tr>
<tr>
<td align="left">Horwitz Defense</td>
<td align="right">440</td>
<td align="right">23</td>
<td align="right">287</td>
<td align="right">750</td>
<td align="right">0.586667</td>
<td align="right">0.0306667</td>
<td align="right">0.382667</td>
</tr>
<tr>
<td align="left">King&#39;s Pawn Game: Wayward Queen Attack</td>
<td align="right">592</td>
<td align="right">22</td>
<td align="right">378</td>
<td align="right">992</td>
<td align="right">0.596774</td>
<td align="right">0.0221774</td>
<td align="right">0.381048</td>
</tr>
</tbody></table>
<h3 id="중위-레이팅">중위 레이팅</h3>
<p>most_count</p>
<table>
<thead>
<tr>
<th align="left"></th>
<th align="right">white</th>
<th align="right">draw</th>
<th align="right">black</th>
<th align="right">count</th>
</tr>
</thead>
<tbody><tr>
<td align="left">Van&#39;t Kruijs Opening</td>
<td align="right">4574</td>
<td align="right">315</td>
<td align="right">5771</td>
<td align="right">10660</td>
</tr>
<tr>
<td align="left">Scandinavian Defense: Mieses-Kotroc Variation</td>
<td align="right">4771</td>
<td align="right">301</td>
<td align="right">2865</td>
<td align="right">7937</td>
</tr>
<tr>
<td align="left">Horwitz Defense</td>
<td align="right">4019</td>
<td align="right">224</td>
<td align="right">3084</td>
<td align="right">7327</td>
</tr>
<tr>
<td align="left">Modern Defense</td>
<td align="right">3529</td>
<td align="right">229</td>
<td align="right">3432</td>
<td align="right">7190</td>
</tr>
<tr>
<td align="left">Owen Defense</td>
<td align="right">3667</td>
<td align="right">221</td>
<td align="right">3297</td>
<td align="right">7185</td>
</tr>
<tr>
<td align="left">Sicilian Defense: Bowdler Attack</td>
<td align="right">2966</td>
<td align="right">191</td>
<td align="right">3465</td>
<td align="right">6622</td>
</tr>
<tr>
<td align="left">Sicilian Defense</td>
<td align="right">2683</td>
<td align="right">205</td>
<td align="right">3411</td>
<td align="right">6299</td>
</tr>
<tr>
<td align="left">French Defense: Knight Variation</td>
<td align="right">3071</td>
<td align="right">193</td>
<td align="right">3016</td>
<td align="right">6280</td>
</tr>
<tr>
<td align="left">Philidor Defense #3</td>
<td align="right">3600</td>
<td align="right">194</td>
<td align="right">2429</td>
<td align="right">6223</td>
</tr>
<tr>
<td align="left">Queen&#39;s Pawn Game #2</td>
<td align="right">2910</td>
<td align="right">217</td>
<td align="right">2577</td>
<td align="right">5704</td>
</tr>
</tbody></table>
<p>most_win_white</p>
<table>
<thead>
<tr>
<th align="left"></th>
<th align="right">white</th>
<th align="right">draw</th>
<th align="right">black</th>
<th align="right">count</th>
<th align="right">white_rate</th>
<th align="right">draw_rate</th>
<th align="right">black_rate</th>
</tr>
</thead>
<tbody><tr>
<td align="left">King&#39;s Pawn</td>
<td align="right">1334</td>
<td align="right">3</td>
<td align="right">55</td>
<td align="right">1392</td>
<td align="right">0.958333</td>
<td align="right">0.00215517</td>
<td align="right">0.0395115</td>
</tr>
<tr>
<td align="left">King&#39;s Pawn Game: Damiano Defense</td>
<td align="right">819</td>
<td align="right">34</td>
<td align="right">321</td>
<td align="right">1174</td>
<td align="right">0.697615</td>
<td align="right">0.0289608</td>
<td align="right">0.273424</td>
</tr>
<tr>
<td align="left">King&#39;s Knight Opening</td>
<td align="right">856</td>
<td align="right">32</td>
<td align="right">372</td>
<td align="right">1260</td>
<td align="right">0.679365</td>
<td align="right">0.0253968</td>
<td align="right">0.295238</td>
</tr>
<tr>
<td align="left">King&#39;s Pawn Game: Nimzowitsch Defense</td>
<td align="right">335</td>
<td align="right">16</td>
<td align="right">156</td>
<td align="right">507</td>
<td align="right">0.66075</td>
<td align="right">0.0315582</td>
<td align="right">0.307692</td>
</tr>
<tr>
<td align="left">Mikenas Defense</td>
<td align="right">440</td>
<td align="right">21</td>
<td align="right">215</td>
<td align="right">676</td>
<td align="right">0.650888</td>
<td align="right">0.0310651</td>
<td align="right">0.318047</td>
</tr>
<tr>
<td align="left">Queen&#39;s Gambit</td>
<td align="right">337</td>
<td align="right">16</td>
<td align="right">167</td>
<td align="right">520</td>
<td align="right">0.648077</td>
<td align="right">0.0307692</td>
<td align="right">0.321154</td>
</tr>
<tr>
<td align="left">King&#39;s Gambit Accepted, King&#39;s Knight Gambit</td>
<td align="right">667</td>
<td align="right">23</td>
<td align="right">349</td>
<td align="right">1039</td>
<td align="right">0.641963</td>
<td align="right">0.0221367</td>
<td align="right">0.3359</td>
</tr>
<tr>
<td align="left">Center Game #2</td>
<td align="right">586</td>
<td align="right">22</td>
<td align="right">311</td>
<td align="right">919</td>
<td align="right">0.63765</td>
<td align="right">0.0239391</td>
<td align="right">0.338411</td>
</tr>
<tr>
<td align="left">Queen&#39;s Pawn Game: Levitsky Attack</td>
<td align="right">714</td>
<td align="right">41</td>
<td align="right">379</td>
<td align="right">1134</td>
<td align="right">0.62963</td>
<td align="right">0.0361552</td>
<td align="right">0.334215</td>
</tr>
<tr>
<td align="left">King&#39;s Gambit Accepted, MacLeod Defense</td>
<td align="right">713</td>
<td align="right">33</td>
<td align="right">399</td>
<td align="right">1145</td>
<td align="right">0.622707</td>
<td align="right">0.028821</td>
<td align="right">0.348472</td>
</tr>
</tbody></table>
<p>most_win_draw</p>
<table>
<thead>
<tr>
<th align="left"></th>
<th align="right">white</th>
<th align="right">draw</th>
<th align="right">black</th>
<th align="right">count</th>
<th align="right">white_rate</th>
<th align="right">draw_rate</th>
<th align="right">black_rate</th>
</tr>
</thead>
<tbody><tr>
<td align="left">Ruy Lopez: Exchange Variation</td>
<td align="right">236</td>
<td align="right">34</td>
<td align="right">312</td>
<td align="right">582</td>
<td align="right">0.405498</td>
<td align="right">0.0584192</td>
<td align="right">0.536082</td>
</tr>
<tr>
<td align="left">Colle System</td>
<td align="right">268</td>
<td align="right">29</td>
<td align="right">260</td>
<td align="right">557</td>
<td align="right">0.481149</td>
<td align="right">0.0520646</td>
<td align="right">0.466786</td>
</tr>
<tr>
<td align="left">Caro-Kann Defense: Advance Variation, Short Variation</td>
<td align="right">218</td>
<td align="right">27</td>
<td align="right">279</td>
<td align="right">524</td>
<td align="right">0.416031</td>
<td align="right">0.0515267</td>
<td align="right">0.532443</td>
</tr>
<tr>
<td align="left">Semi-Slav Defense: Accelerated Move Order</td>
<td align="right">378</td>
<td align="right">34</td>
<td align="right">289</td>
<td align="right">701</td>
<td align="right">0.53923</td>
<td align="right">0.0485021</td>
<td align="right">0.412268</td>
</tr>
<tr>
<td align="left">Slav Defense</td>
<td align="right">455</td>
<td align="right">46</td>
<td align="right">451</td>
<td align="right">952</td>
<td align="right">0.477941</td>
<td align="right">0.0483193</td>
<td align="right">0.473739</td>
</tr>
<tr>
<td align="left">Kadas Opening</td>
<td align="right">194</td>
<td align="right">25</td>
<td align="right">301</td>
<td align="right">520</td>
<td align="right">0.373077</td>
<td align="right">0.0480769</td>
<td align="right">0.578846</td>
</tr>
<tr>
<td align="left">English Opening: Symmetrical Variation</td>
<td align="right">251</td>
<td align="right">24</td>
<td align="right">229</td>
<td align="right">504</td>
<td align="right">0.498016</td>
<td align="right">0.047619</td>
<td align="right">0.454365</td>
</tr>
<tr>
<td align="left">Pirc Defense #5</td>
<td align="right">548</td>
<td align="right">47</td>
<td align="right">429</td>
<td align="right">1024</td>
<td align="right">0.535156</td>
<td align="right">0.0458984</td>
<td align="right">0.418945</td>
</tr>
<tr>
<td align="left">Franco-Benoni Defense</td>
<td align="right">251</td>
<td align="right">24</td>
<td align="right">260</td>
<td align="right">535</td>
<td align="right">0.469159</td>
<td align="right">0.0448598</td>
<td align="right">0.485981</td>
</tr>
<tr>
<td align="left">Zukertort Opening: Sicilian Invitation</td>
<td align="right">332</td>
<td align="right">28</td>
<td align="right">270</td>
<td align="right">630</td>
<td align="right">0.526984</td>
<td align="right">0.0444444</td>
<td align="right">0.428571</td>
</tr>
</tbody></table>
<p>most_win_black</p>
<table>
<thead>
<tr>
<th align="left"></th>
<th align="right">white</th>
<th align="right">draw</th>
<th align="right">black</th>
<th align="right">count</th>
<th align="right">white_rate</th>
<th align="right">draw_rate</th>
<th align="right">black_rate</th>
</tr>
</thead>
<tbody><tr>
<td align="left">?</td>
<td align="right">589</td>
<td align="right">1</td>
<td align="right">2270</td>
<td align="right">2860</td>
<td align="right">0.205944</td>
<td align="right">0.00034965</td>
<td align="right">0.793706</td>
</tr>
<tr>
<td align="left">King&#39;s Pawn Game</td>
<td align="right">622</td>
<td align="right">64</td>
<td align="right">1078</td>
<td align="right">1764</td>
<td align="right">0.352608</td>
<td align="right">0.0362812</td>
<td align="right">0.611111</td>
</tr>
<tr>
<td align="left">Center Game: Normal Variation</td>
<td align="right">472</td>
<td align="right">30</td>
<td align="right">785</td>
<td align="right">1287</td>
<td align="right">0.366744</td>
<td align="right">0.02331</td>
<td align="right">0.609946</td>
</tr>
<tr>
<td align="left">Kadas Opening</td>
<td align="right">194</td>
<td align="right">25</td>
<td align="right">301</td>
<td align="right">520</td>
<td align="right">0.373077</td>
<td align="right">0.0480769</td>
<td align="right">0.578846</td>
</tr>
<tr>
<td align="left">Sicilian Defense: Smith-Morra Gambit #2</td>
<td align="right">779</td>
<td align="right">64</td>
<td align="right">1075</td>
<td align="right">1918</td>
<td align="right">0.406152</td>
<td align="right">0.0333681</td>
<td align="right">0.56048</td>
</tr>
<tr>
<td align="left">French Defense: Advance Variation, Nimzowitsch System</td>
<td align="right">355</td>
<td align="right">22</td>
<td align="right">475</td>
<td align="right">852</td>
<td align="right">0.416667</td>
<td align="right">0.0258216</td>
<td align="right">0.557512</td>
</tr>
<tr>
<td align="left">Caro-Kann Defense: Hillbilly Attack</td>
<td align="right">414</td>
<td align="right">40</td>
<td align="right">557</td>
<td align="right">1011</td>
<td align="right">0.409496</td>
<td align="right">0.0395648</td>
<td align="right">0.55094</td>
</tr>
<tr>
<td align="left">French Defense #2</td>
<td align="right">1152</td>
<td align="right">87</td>
<td align="right">1491</td>
<td align="right">2730</td>
<td align="right">0.421978</td>
<td align="right">0.0318681</td>
<td align="right">0.546154</td>
</tr>
<tr>
<td align="left">Sicilian Defense</td>
<td align="right">2683</td>
<td align="right">205</td>
<td align="right">3411</td>
<td align="right">6299</td>
<td align="right">0.425941</td>
<td align="right">0.0325448</td>
<td align="right">0.541515</td>
</tr>
<tr>
<td align="left">Van&#39;t Kruijs Opening</td>
<td align="right">4574</td>
<td align="right">315</td>
<td align="right">5771</td>
<td align="right">10660</td>
<td align="right">0.429081</td>
<td align="right">0.0295497</td>
<td align="right">0.54137</td>
</tr>
</tbody></table>
<h3 id="상위-레이팅">상위 레이팅</h3>
<p>most_count</p>
<table>
<thead>
<tr>
<th align="left"></th>
<th align="right">white</th>
<th align="right">draw</th>
<th align="right">black</th>
<th align="right">count</th>
</tr>
</thead>
<tbody><tr>
<td align="left">Van&#39;t Kruijs Opening</td>
<td align="right">2101</td>
<td align="right">168</td>
<td align="right">2772</td>
<td align="right">5041</td>
</tr>
<tr>
<td align="left">Modern Defense</td>
<td align="right">2415</td>
<td align="right">167</td>
<td align="right">2383</td>
<td align="right">4965</td>
</tr>
<tr>
<td align="left">Caro-Kann Defense</td>
<td align="right">2008</td>
<td align="right">203</td>
<td align="right">2431</td>
<td align="right">4642</td>
</tr>
<tr>
<td align="left">Horwitz Defense</td>
<td align="right">2024</td>
<td align="right">162</td>
<td align="right">1811</td>
<td align="right">3997</td>
</tr>
<tr>
<td align="left">Owen Defense</td>
<td align="right">2061</td>
<td align="right">148</td>
<td align="right">1672</td>
<td align="right">3881</td>
</tr>
<tr>
<td align="left">Sicilian Defense</td>
<td align="right">1280</td>
<td align="right">138</td>
<td align="right">2004</td>
<td align="right">3422</td>
</tr>
<tr>
<td align="left">Scandinavian Defense: Mieses-Kotroc Variation</td>
<td align="right">1708</td>
<td align="right">170</td>
<td align="right">1543</td>
<td align="right">3421</td>
</tr>
<tr>
<td align="left">French Defense: Knight Variation</td>
<td align="right">1381</td>
<td align="right">150</td>
<td align="right">1786</td>
<td align="right">3317</td>
</tr>
<tr>
<td align="left">Queen&#39;s Pawn</td>
<td align="right">1651</td>
<td align="right">113</td>
<td align="right">1132</td>
<td align="right">2896</td>
</tr>
<tr>
<td align="left">Hungarian Opening</td>
<td align="right">1148</td>
<td align="right">77</td>
<td align="right">1313</td>
<td align="right">2538</td>
</tr>
</tbody></table>
<p>most_win_white</p>
<table>
<thead>
<tr>
<th align="left"></th>
<th align="right">white</th>
<th align="right">draw</th>
<th align="right">black</th>
<th align="right">count</th>
<th align="right">white_rate</th>
<th align="right">draw_rate</th>
<th align="right">black_rate</th>
</tr>
</thead>
<tbody><tr>
<td align="left">King&#39;s Pawn</td>
<td align="right">958</td>
<td align="right">2</td>
<td align="right">21</td>
<td align="right">981</td>
<td align="right">0.976555</td>
<td align="right">0.00203874</td>
<td align="right">0.0214067</td>
</tr>
<tr>
<td align="left">Philidor Defense</td>
<td align="right">337</td>
<td align="right">18</td>
<td align="right">149</td>
<td align="right">504</td>
<td align="right">0.668651</td>
<td align="right">0.0357143</td>
<td align="right">0.295635</td>
</tr>
<tr>
<td align="left">Queen&#39;s Gambit Refused: Marshall Defense</td>
<td align="right">586</td>
<td align="right">46</td>
<td align="right">346</td>
<td align="right">978</td>
<td align="right">0.599182</td>
<td align="right">0.0470348</td>
<td align="right">0.353783</td>
</tr>
<tr>
<td align="left">Queen&#39;s Pawn</td>
<td align="right">1651</td>
<td align="right">113</td>
<td align="right">1132</td>
<td align="right">2896</td>
<td align="right">0.570097</td>
<td align="right">0.0390193</td>
<td align="right">0.390884</td>
</tr>
<tr>
<td align="left">Slav Defense: Three Knights Variation</td>
<td align="right">304</td>
<td align="right">25</td>
<td align="right">207</td>
<td align="right">536</td>
<td align="right">0.567164</td>
<td align="right">0.0466418</td>
<td align="right">0.386194</td>
</tr>
<tr>
<td align="left">Rat Defense: Small Center Defense</td>
<td align="right">407</td>
<td align="right">28</td>
<td align="right">287</td>
<td align="right">722</td>
<td align="right">0.563712</td>
<td align="right">0.0387812</td>
<td align="right">0.397507</td>
</tr>
<tr>
<td align="left">English Opening: Great Snake Variation</td>
<td align="right">343</td>
<td align="right">35</td>
<td align="right">240</td>
<td align="right">618</td>
<td align="right">0.555016</td>
<td align="right">0.0566343</td>
<td align="right">0.38835</td>
</tr>
<tr>
<td align="left">Queen&#39;s Gambit Accepted</td>
<td align="right">354</td>
<td align="right">29</td>
<td align="right">256</td>
<td align="right">639</td>
<td align="right">0.553991</td>
<td align="right">0.0453834</td>
<td align="right">0.400626</td>
</tr>
<tr>
<td align="left">French Defense: Normal Variation</td>
<td align="right">765</td>
<td align="right">67</td>
<td align="right">552</td>
<td align="right">1384</td>
<td align="right">0.552746</td>
<td align="right">0.0484104</td>
<td align="right">0.398844</td>
</tr>
<tr>
<td align="left">Queen&#39;s Gambit Declined: Queen&#39;s Knight Variation</td>
<td align="right">360</td>
<td align="right">42</td>
<td align="right">252</td>
<td align="right">654</td>
<td align="right">0.550459</td>
<td align="right">0.0642202</td>
<td align="right">0.385321</td>
</tr>
</tbody></table>
<p>most_win_draw</p>
<table>
<thead>
<tr>
<th align="left"></th>
<th align="right">white</th>
<th align="right">draw</th>
<th align="right">black</th>
<th align="right">count</th>
<th align="right">white_rate</th>
<th align="right">draw_rate</th>
<th align="right">black_rate</th>
</tr>
</thead>
<tbody><tr>
<td align="left">Queen&#39;s Pawn Game: London System</td>
<td align="right">225</td>
<td align="right">46</td>
<td align="right">271</td>
<td align="right">542</td>
<td align="right">0.415129</td>
<td align="right">0.0848708</td>
<td align="right">0.5</td>
</tr>
<tr>
<td align="left">French Defense: Exchange Variation</td>
<td align="right">751</td>
<td align="right">135</td>
<td align="right">846</td>
<td align="right">1732</td>
<td align="right">0.433603</td>
<td align="right">0.0779446</td>
<td align="right">0.488453</td>
</tr>
<tr>
<td align="left">English Opening: Anglo-Indian Defense, Queen&#39;s Knight Variation</td>
<td align="right">269</td>
<td align="right">37</td>
<td align="right">224</td>
<td align="right">530</td>
<td align="right">0.507547</td>
<td align="right">0.0698113</td>
<td align="right">0.422642</td>
</tr>
<tr>
<td align="left">French Defense: Exchange Variation, Monte Carlo Variation</td>
<td align="right">204</td>
<td align="right">36</td>
<td align="right">305</td>
<td align="right">545</td>
<td align="right">0.374312</td>
<td align="right">0.066055</td>
<td align="right">0.559633</td>
</tr>
<tr>
<td align="left">Sicilian Defense: Loewenthal Variation</td>
<td align="right">269</td>
<td align="right">38</td>
<td align="right">275</td>
<td align="right">582</td>
<td align="right">0.462199</td>
<td align="right">0.0652921</td>
<td align="right">0.472509</td>
</tr>
<tr>
<td align="left">Queen&#39;s Pawn Game: Mason Attack</td>
<td align="right">394</td>
<td align="right">53</td>
<td align="right">376</td>
<td align="right">823</td>
<td align="right">0.478736</td>
<td align="right">0.0643985</td>
<td align="right">0.456865</td>
</tr>
<tr>
<td align="left">Bird Opening: Dutch Variation</td>
<td align="right">491</td>
<td align="right">68</td>
<td align="right">499</td>
<td align="right">1058</td>
<td align="right">0.464083</td>
<td align="right">0.0642722</td>
<td align="right">0.471645</td>
</tr>
<tr>
<td align="left">Queen&#39;s Gambit Declined: Queen&#39;s Knight Variation</td>
<td align="right">360</td>
<td align="right">42</td>
<td align="right">252</td>
<td align="right">654</td>
<td align="right">0.550459</td>
<td align="right">0.0642202</td>
<td align="right">0.385321</td>
</tr>
<tr>
<td align="left">Zukertort Opening: Queen&#39;s Gambit Invitation</td>
<td align="right">385</td>
<td align="right">50</td>
<td align="right">349</td>
<td align="right">784</td>
<td align="right">0.491071</td>
<td align="right">0.0637755</td>
<td align="right">0.445153</td>
</tr>
<tr>
<td align="left">Queen&#39;s Pawn Game: Zukertort Variation</td>
<td align="right">1047</td>
<td align="right">135</td>
<td align="right">970</td>
<td align="right">2152</td>
<td align="right">0.486524</td>
<td align="right">0.0627323</td>
<td align="right">0.450743</td>
</tr>
</tbody></table>
<p>most_win_black</p>
<table>
<thead>
<tr>
<th align="left"></th>
<th align="right">white</th>
<th align="right">draw</th>
<th align="right">black</th>
<th align="right">count</th>
<th align="right">white_rate</th>
<th align="right">draw_rate</th>
<th align="right">black_rate</th>
</tr>
</thead>
<tbody><tr>
<td align="left">?</td>
<td align="right">362</td>
<td align="right">4</td>
<td align="right">1909</td>
<td align="right">2275</td>
<td align="right">0.159121</td>
<td align="right">0.00175824</td>
<td align="right">0.839121</td>
</tr>
<tr>
<td align="left">Sicilian Defense: Smith-Morra Gambit #2</td>
<td align="right">233</td>
<td align="right">13</td>
<td align="right">412</td>
<td align="right">658</td>
<td align="right">0.354103</td>
<td align="right">0.0197568</td>
<td align="right">0.62614</td>
</tr>
<tr>
<td align="left">French Defense #2</td>
<td align="right">327</td>
<td align="right">33</td>
<td align="right">573</td>
<td align="right">933</td>
<td align="right">0.350482</td>
<td align="right">0.0353698</td>
<td align="right">0.614148</td>
</tr>
<tr>
<td align="left">Sicilian Defense: Bowdler Attack</td>
<td align="right">875</td>
<td align="right">103</td>
<td align="right">1533</td>
<td align="right">2511</td>
<td align="right">0.348467</td>
<td align="right">0.0410195</td>
<td align="right">0.610514</td>
</tr>
<tr>
<td align="left">Benoni Defense: Benoni Gambit Accepted</td>
<td align="right">187</td>
<td align="right">20</td>
<td align="right">310</td>
<td align="right">517</td>
<td align="right">0.361702</td>
<td align="right">0.0386847</td>
<td align="right">0.599613</td>
</tr>
<tr>
<td align="left">King&#39;s Pawn Game: Leonardis Variation</td>
<td align="right">403</td>
<td align="right">46</td>
<td align="right">641</td>
<td align="right">1090</td>
<td align="right">0.369725</td>
<td align="right">0.0422018</td>
<td align="right">0.588073</td>
</tr>
<tr>
<td align="left">Sicilian Defense</td>
<td align="right">1280</td>
<td align="right">138</td>
<td align="right">2004</td>
<td align="right">3422</td>
<td align="right">0.37405</td>
<td align="right">0.0403273</td>
<td align="right">0.585622</td>
</tr>
<tr>
<td align="left">Hungarian Opening: Catalan Formation</td>
<td align="right">204</td>
<td align="right">20</td>
<td align="right">302</td>
<td align="right">526</td>
<td align="right">0.387833</td>
<td align="right">0.0380228</td>
<td align="right">0.574144</td>
</tr>
<tr>
<td align="left">Saragossa Opening</td>
<td align="right">233</td>
<td align="right">18</td>
<td align="right">337</td>
<td align="right">588</td>
<td align="right">0.396259</td>
<td align="right">0.0306122</td>
<td align="right">0.573129</td>
</tr>
<tr>
<td align="left">French Defense: La Bourdonnais Variation</td>
<td align="right">551</td>
<td align="right">54</td>
<td align="right">790</td>
<td align="right">1395</td>
<td align="right">0.394982</td>
<td align="right">0.0387097</td>
<td align="right">0.566308</td>
</tr>
</tbody></table>
<h3 id="전체-레이팅">전체 레이팅</h3>
<p>most_count</p>
<table>
<thead>
<tr>
<th align="left"></th>
<th align="right">white</th>
<th align="right">draw</th>
<th align="right">black</th>
<th align="right">count</th>
</tr>
</thead>
<tbody><tr>
<td align="left">Van&#39;t Kruijs Opening</td>
<td align="right">7584</td>
<td align="right">523</td>
<td align="right">9280</td>
<td align="right">17387</td>
</tr>
<tr>
<td align="left">Modern Defense</td>
<td align="right">6265</td>
<td align="right">412</td>
<td align="right">5990</td>
<td align="right">12667</td>
</tr>
<tr>
<td align="left">Scandinavian Defense: Mieses-Kotroc Variation</td>
<td align="right">7184</td>
<td align="right">496</td>
<td align="right">4683</td>
<td align="right">12363</td>
</tr>
<tr>
<td align="left">Horwitz Defense</td>
<td align="right">6483</td>
<td align="right">409</td>
<td align="right">5182</td>
<td align="right">12074</td>
</tr>
<tr>
<td align="left">Owen Defense</td>
<td align="right">5998</td>
<td align="right">381</td>
<td align="right">5177</td>
<td align="right">11556</td>
</tr>
<tr>
<td align="left">Caro-Kann Defense</td>
<td align="right">4860</td>
<td align="right">393</td>
<td align="right">5166</td>
<td align="right">10419</td>
</tr>
<tr>
<td align="left">Sicilian Defense</td>
<td align="right">4216</td>
<td align="right">357</td>
<td align="right">5679</td>
<td align="right">10252</td>
</tr>
<tr>
<td align="left">French Defense: Knight Variation</td>
<td align="right">4763</td>
<td align="right">359</td>
<td align="right">5005</td>
<td align="right">10127</td>
</tr>
<tr>
<td align="left">Sicilian Defense: Bowdler Attack</td>
<td align="right">4007</td>
<td align="right">306</td>
<td align="right">5167</td>
<td align="right">9480</td>
</tr>
<tr>
<td align="left">Scandinavian Defense</td>
<td align="right">4190</td>
<td align="right">293</td>
<td align="right">4663</td>
<td align="right">9146</td>
</tr>
</tbody></table>
<p>most_win_white</p>
<table>
<thead>
<tr>
<th align="left"></th>
<th align="right">white</th>
<th align="right">draw</th>
<th align="right">black</th>
<th align="right">count</th>
<th align="right">white_rate</th>
<th align="right">draw_rate</th>
<th align="right">black_rate</th>
</tr>
</thead>
<tbody><tr>
<td align="left">King&#39;s Pawn</td>
<td align="right">2351</td>
<td align="right">5</td>
<td align="right">85</td>
<td align="right">2441</td>
<td align="right">0.96313</td>
<td align="right">0.00204834</td>
<td align="right">0.0348218</td>
</tr>
<tr>
<td align="left">Italian Game: Two Knights Defense, Fried Liver Attack</td>
<td align="right">373</td>
<td align="right">12</td>
<td align="right">121</td>
<td align="right">506</td>
<td align="right">0.737154</td>
<td align="right">0.0237154</td>
<td align="right">0.23913</td>
</tr>
<tr>
<td align="left">Russian Game: Damiano Variation</td>
<td align="right">418</td>
<td align="right">16</td>
<td align="right">154</td>
<td align="right">588</td>
<td align="right">0.710884</td>
<td align="right">0.0272109</td>
<td align="right">0.261905</td>
</tr>
<tr>
<td align="left">King&#39;s Knight Opening</td>
<td align="right">1195</td>
<td align="right">45</td>
<td align="right">485</td>
<td align="right">1725</td>
<td align="right">0.692754</td>
<td align="right">0.026087</td>
<td align="right">0.281159</td>
</tr>
<tr>
<td align="left">King&#39;s Pawn Game: Damiano Defense</td>
<td align="right">1166</td>
<td align="right">59</td>
<td align="right">474</td>
<td align="right">1699</td>
<td align="right">0.686286</td>
<td align="right">0.0347263</td>
<td align="right">0.278988</td>
</tr>
<tr>
<td align="left">King&#39;s Pawn Game: Nimzowitsch Defense</td>
<td align="right">448</td>
<td align="right">20</td>
<td align="right">211</td>
<td align="right">679</td>
<td align="right">0.659794</td>
<td align="right">0.0294551</td>
<td align="right">0.310751</td>
</tr>
<tr>
<td align="left">Queen&#39;s Gambit</td>
<td align="right">469</td>
<td align="right">23</td>
<td align="right">224</td>
<td align="right">716</td>
<td align="right">0.655028</td>
<td align="right">0.0321229</td>
<td align="right">0.312849</td>
</tr>
<tr>
<td align="left">Scotch Game: Scotch Gambit</td>
<td align="right">379</td>
<td align="right">19</td>
<td align="right">190</td>
<td align="right">588</td>
<td align="right">0.644558</td>
<td align="right">0.0323129</td>
<td align="right">0.323129</td>
</tr>
<tr>
<td align="left">Vienna Game: Vienna Gambit</td>
<td align="right">323</td>
<td align="right">13</td>
<td align="right">175</td>
<td align="right">511</td>
<td align="right">0.632094</td>
<td align="right">0.0254403</td>
<td align="right">0.342466</td>
</tr>
<tr>
<td align="left">King&#39;s Gambit Accepted, King&#39;s Knight Gambit</td>
<td align="right">881</td>
<td align="right">34</td>
<td align="right">481</td>
<td align="right">1396</td>
<td align="right">0.631089</td>
<td align="right">0.0243553</td>
<td align="right">0.344556</td>
</tr>
</tbody></table>
<p>most_win_draw</p>
<table>
<thead>
<tr>
<th align="left"></th>
<th align="right">white</th>
<th align="right">draw</th>
<th align="right">black</th>
<th align="right">count</th>
<th align="right">white_rate</th>
<th align="right">draw_rate</th>
<th align="right">black_rate</th>
</tr>
</thead>
<tbody><tr>
<td align="left">Queen&#39;s Pawn Game: London System</td>
<td align="right">497</td>
<td align="right">64</td>
<td align="right">476</td>
<td align="right">1037</td>
<td align="right">0.479267</td>
<td align="right">0.0617165</td>
<td align="right">0.459016</td>
</tr>
<tr>
<td align="left">Scandinavian Defense: Gubinsky-Melts Defense</td>
<td align="right">389</td>
<td align="right">49</td>
<td align="right">382</td>
<td align="right">820</td>
<td align="right">0.47439</td>
<td align="right">0.0597561</td>
<td align="right">0.465854</td>
</tr>
<tr>
<td align="left">English Opening: Anglo-Indian Defense, Queen&#39;s Knight Variation</td>
<td align="right">400</td>
<td align="right">45</td>
<td align="right">318</td>
<td align="right">763</td>
<td align="right">0.524246</td>
<td align="right">0.0589777</td>
<td align="right">0.416776</td>
</tr>
<tr>
<td align="left">French Defense: Exchange Variation</td>
<td align="right">1570</td>
<td align="right">192</td>
<td align="right">1584</td>
<td align="right">3346</td>
<td align="right">0.469217</td>
<td align="right">0.0573819</td>
<td align="right">0.473401</td>
</tr>
<tr>
<td align="left">Sicilian Defense: Canal Attack, Main Line</td>
<td align="right">253</td>
<td align="right">29</td>
<td align="right">236</td>
<td align="right">518</td>
<td align="right">0.488417</td>
<td align="right">0.0559846</td>
<td align="right">0.455598</td>
</tr>
<tr>
<td align="left">French Defense: Exchange Variation, Monte Carlo Variation</td>
<td align="right">334</td>
<td align="right">42</td>
<td align="right">420</td>
<td align="right">796</td>
<td align="right">0.419598</td>
<td align="right">0.0527638</td>
<td align="right">0.527638</td>
</tr>
<tr>
<td align="left">English Opening: Symmetrical Variation, Normal Variation</td>
<td align="right">348</td>
<td align="right">35</td>
<td align="right">282</td>
<td align="right">665</td>
<td align="right">0.523308</td>
<td align="right">0.0526316</td>
<td align="right">0.42406</td>
</tr>
<tr>
<td align="left">Queen&#39;s Gambit Declined: Three Knights Variation</td>
<td align="right">452</td>
<td align="right">46</td>
<td align="right">380</td>
<td align="right">878</td>
<td align="right">0.514806</td>
<td align="right">0.0523918</td>
<td align="right">0.432802</td>
</tr>
<tr>
<td align="left">English Opening: Anglo-Indian Defense</td>
<td align="right">357</td>
<td align="right">41</td>
<td align="right">387</td>
<td align="right">785</td>
<td align="right">0.454777</td>
<td align="right">0.0522293</td>
<td align="right">0.492994</td>
</tr>
<tr>
<td align="left">Caro-Kann Defense: Classical Variation</td>
<td align="right">330</td>
<td align="right">35</td>
<td align="right">308</td>
<td align="right">673</td>
<td align="right">0.490342</td>
<td align="right">0.0520059</td>
<td align="right">0.457652</td>
</tr>
</tbody></table>
<p>most_win_black</p>
<table>
<thead>
<tr>
<th align="left"></th>
<th align="right">white</th>
<th align="right">draw</th>
<th align="right">black</th>
<th align="right">count</th>
<th align="right">white_rate</th>
<th align="right">draw_rate</th>
<th align="right">black_rate</th>
</tr>
</thead>
<tbody><tr>
<td align="left">?</td>
<td align="right">975</td>
<td align="right">5</td>
<td align="right">4243</td>
<td align="right">5223</td>
<td align="right">0.186674</td>
<td align="right">0.000957304</td>
<td align="right">0.812368</td>
</tr>
<tr>
<td align="left">King&#39;s Pawn Game</td>
<td align="right">819</td>
<td align="right">91</td>
<td align="right">1491</td>
<td align="right">2401</td>
<td align="right">0.341108</td>
<td align="right">0.0379009</td>
<td align="right">0.620991</td>
</tr>
<tr>
<td align="left">Center Game: Normal Variation</td>
<td align="right">583</td>
<td align="right">45</td>
<td align="right">1000</td>
<td align="right">1628</td>
<td align="right">0.358108</td>
<td align="right">0.0276413</td>
<td align="right">0.614251</td>
</tr>
<tr>
<td align="left">Ware Opening</td>
<td align="right">251</td>
<td align="right">29</td>
<td align="right">432</td>
<td align="right">712</td>
<td align="right">0.352528</td>
<td align="right">0.0407303</td>
<td align="right">0.606742</td>
</tr>
<tr>
<td align="left">French Defense: Advance Variation #4</td>
<td align="right">248</td>
<td align="right">25</td>
<td align="right">413</td>
<td align="right">686</td>
<td align="right">0.361516</td>
<td align="right">0.0364431</td>
<td align="right">0.602041</td>
</tr>
<tr>
<td align="left">Scandinavian Defense: Panov Transfer</td>
<td align="right">197</td>
<td align="right">17</td>
<td align="right">313</td>
<td align="right">527</td>
<td align="right">0.373814</td>
<td align="right">0.0322581</td>
<td align="right">0.593928</td>
</tr>
<tr>
<td align="left">French Defense: Advance Variation</td>
<td align="right">302</td>
<td align="right">32</td>
<td align="right">471</td>
<td align="right">805</td>
<td align="right">0.375155</td>
<td align="right">0.0397516</td>
<td align="right">0.585093</td>
</tr>
<tr>
<td align="left">Indian Game: East Indian Defense</td>
<td align="right">247</td>
<td align="right">16</td>
<td align="right">363</td>
<td align="right">626</td>
<td align="right">0.394569</td>
<td align="right">0.0255591</td>
<td align="right">0.579872</td>
</tr>
<tr>
<td align="left">French Defense: Advance Variation, Nimzowitsch System</td>
<td align="right">502</td>
<td align="right">42</td>
<td align="right">742</td>
<td align="right">1286</td>
<td align="right">0.390358</td>
<td align="right">0.0326594</td>
<td align="right">0.576983</td>
</tr>
<tr>
<td align="left">Kadas Opening</td>
<td align="right">301</td>
<td align="right">31</td>
<td align="right">450</td>
<td align="right">782</td>
<td align="right">0.38491</td>
<td align="right">0.0396419</td>
<td align="right">0.575448</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[Chess Opening database Preprocessing]]></title>
            <link>https://velog.io/@4hyoungsoo_/Chess-Opening-database-Preprocessing</link>
            <guid>https://velog.io/@4hyoungsoo_/Chess-Opening-database-Preprocessing</guid>
            <pubDate>Thu, 29 Dec 2022 05:14:29 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>이전 포스팅에서는 lichess에서 제공한 체스 오프닝 데이터를 간단하게 전처리 했다. 이번엔 본격적으로 우리가 데이터베이스에 저장할 포맷으로 전처리를 진행한다.</p>
</blockquote>
<h2 id="데이터-구조">데이터 구조</h2>
<p>데이터를 전처리하기전에 어떤식으로 구조를 짜야 쿼리를 쉽고 빠르게 할 수 있을지에 대해서 고민을 해보다 2가지 선택지를 생각했다.</p>
<ul>
<li>double linked list</li>
<li>hash table</li>
</ul>
<p>결론부터 말하자면 hash table (dict)의 구조를 채용하여 전처리 하기로 하였다.</p>
<p>double linked list의 구조도 역시 활용할만 하였으나 여러 예외처리들과 오프닝 데이터를 쿼리를 할 때 특정 오프닝의 이름을 알기 위해서 끝까지 탐색해야 한다는 점이 비효율적이라고 생각했다.</p>
<p>체스 기보를 나타내는 방식엔 pgn방식과 uci방식이 있는데 후에 stockfish를 활용하기 위하여 stockfish와 호환이 잘되는 uci방식으로 데이터를 저장한다.</p>
<blockquote>
<p>스톡피시는 꽤 오랜 기간동안 사용된 대중에게 공개된 가장 강력한 체스 엔진입니다. 무료 오픈 소스 엔진인 스톡피시는 현재 사람들이 자발적으로 참여하여 개발되고 있습니다. 스톡피시는 2004년 토르드 롬스타드(Tord Romstad)가 개발한 엔진을 기반으로 하며, 이후 마르코 코스탈바(Marco Costalba)가 2008년 이를 발전시켰습니다. 주나 키이스키(Joona Kiiski)와 게리 린스콧(Gary Linscott)또한 창립자로 여겨집니다.
출처 (<a href="https://www.chess.com/ko/terms/stockfish-chess-engine-ko#what">https://www.chess.com/ko/terms/stockfish-chess-engine-ko#what</a>)</p>
</blockquote>
<pre><code class="language-python">#pipelines.py
import pandas as pd
from .utils import _revmove_number


FPATH = &quot;&lt;path&gt;&quot;
FNAME = &#39;pre_data.csv&#39;

class PreProcessing:
    def __init__(self, fpath) -&gt; None:
        self.fname = FNAME
        self.fpath = FPATH
        self.__fpath = fpath
        self.raw_data = None
        self.data_preprocessing()

    def data_preprocessing(self):
        df =self.import_data_csv(fpath=self.__fpath)
        self.raw_data = df
        df.to_csv(f&#39;{self.fpath}{self.fname}&#39;)


    def import_data_csv(self, fpath, sep = &#39;\t&#39;):
      data = pd.read_csv(fpath, sep=sep)
      df = self.split_data(data)

      df = pd.DataFrame(df, columns=[&#39;pgn&#39;,&#39;uci&#39;,&#39;name&#39;,&#39;wdl&#39;])

      return df


    def split_data(self, data):
      df = []
      for i in data.index:
        val = data.loc[i, &#39;uci&#39;].split(&#39; &#39;)
        pgn_val = data.loc[i, &#39;pgn&#39;].split(&#39; &#39;)
        k = _revmove_number(pgn_val)
        name = data.loc[i, &#39;name&#39;]
        df.append([k,val,name,&#39;&#39;])

      df.sort(key=lambda x: len(x[0]))

      return df

</code></pre>
<pre><code class="language-python">#process.py
import pandas as pd
from ast import literal_eval
import csv
DEFAULT_FILE_NAME = &#39;preprocessing_opening.csv&#39;
FPATH = &quot;C:\\Users\\aaa57\\chess\\dist\\&quot;

class Hash:
  def __init__(self) -&gt; None:
    self.default_dic = {
          &#39;next&#39; : [],
          &#39;name&#39; : &#39;default&#39;,
        }

class ProcessData:
  def __init__(self,data) -&gt; None:
    self.data = data
    self.hash_data = {
      &#39;start&#39; : Hash().default_dic
    }

    for i in self.data.index:
      try:
        self.to_hash(literal_eval(self.data.loc[i,&#39;uci&#39;]), self.data.loc[i,&#39;name&#39;])
      except:
        self.to_hash(self.data.loc[i,&#39;uci&#39;], self.data.loc[i,&#39;name&#39;])

    self.to_csv()

  def to_hash(self, uci, name):
    if len(uci) == 1:
      self.hash_data[str(uci)] = Hash().default_dic
      self.hash_data[&#39;start&#39;][&#39;next&#39;].append(uci[-1])
      self.hash_data[str(uci)][&#39;name&#39;] = name

    else:
      try:
        self.hash_data[str(uci[:-1])][&#39;next&#39;].append(uci[-1])
      except:
        self.to_hash(uci[:-1],name)
        self.hash_data[str(uci[:-1])][&#39;next&#39;].append(uci[-1])

      self.hash_data[str(uci)] = Hash().default_dic
      self.hash_data[str(uci)][&#39;name&#39;] = name

  def to_csv(self):
    with open(f&#39;{FPATH}{DEFAULT_FILE_NAME}&#39;, &quot;w&quot;, newline=&quot;&quot;, encoding=&#39;utf-8&#39;) as csv_file:
    # Create a CSV writer object
      writer = csv.writer(csv_file)

      # Write the header row
      writer.writerow([&quot;Move&quot;, &quot;Next Moves&quot;, &quot;Opening Name&quot;])

      # Iterate over the dictionary and write each row to the CSV file
      for move, details in self.hash_data.items():
        # Convert the string representation of the list back to a list
        if move != &#39;start&#39;:
          move = eval(move)
        next_moves = &quot;,&quot;.join(details[&quot;next&quot;])
        writer.writerow([move, next_moves, details[&quot;name&quot;]])


class ProcessUtil:

  def to_hash(self, row):
    if len(row[&#39;pgn&#39;]) == 1:
      return


</code></pre>
<p>데이터가 생성되면 pipelines.py 에서 1차적으로 데이터를 추출 변형시키고 process.py에서 1차적으로 처리된 데이터를 데이터베이스에 저장할 수 있도록 hash table형태로 저장한다.</p>
<pre><code class="language-python">#Processor.py
from .pipelines import PreProcessing
from process.process import ProcessData


class DataProcessor:
  def __init__(self):
    self.data = None

    self.data_processor(&quot;C:\\Users\\aaa57\\chess\\dist\\chess_opening.csv&quot;)
    self.process()

  def data_processor(self, fpath):
    self.data = PreProcessing(fpath=fpath).raw_data

  def process(self):
    ProcessData(self.data)

</code></pre>
<p>후에 지속적으로 체스 기보 데이터가 들어올 때마다 코드를 일일히 실행하는 것은 비효율적이기 때문에 DataProcessor라는 객체를 생성해 코드를 최소한으로 작성해 실행할 수 있도록 하였다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Chess Opening database 구축]]></title>
            <link>https://velog.io/@4hyoungsoo_/Chess-Opening-database-%EA%B5%AC%EC%B6%95</link>
            <guid>https://velog.io/@4hyoungsoo_/Chess-Opening-database-%EA%B5%AC%EC%B6%95</guid>
            <pubDate>Tue, 27 Dec 2022 06:04:39 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>이번 프로젝트의 구성은 Stockfish를 활용하여 Chess engine과의 대결을 할 수 있는 사이트와, chess 기보를 읽어들이는 data pipeline, 그 데이터를 저장하는 data warehouse를 구성하는 것이 목표.</p>
</blockquote>
<h2 id="why-chess">Why Chess?</h2>
<p>평소 체스와 바둑 장기 등 여러 보드게임을 즐겨하는 중에 체스에 대한 매력을 느껴 여러 사이트를 전전하던 중 사람들과 대결한 기보를 체스 엔진에다가 분석을 맡기는 기능을 유료로 서비스하는 사이트들이 많았다.</p>
<p>물론 lichess같이 무료로 모든 것을 제공하는 사이트도 있지만, datapipeline을 구축해보고 엄청난 data(약 1.2TB)를 다뤄볼 수 있다는게 엄청난 매력 아닌가.</p>
<p>이번 프로젝트를 통해 대용량 데이터를 관계형 데이터베이스(MYSQL, POSTGRESSQL)과 NoSQL(MongoDB, HBASE)를 활용해서 대용량 데이터베이스에서 빠른 쿼리 응답을 수행할 수 있도록 하는 것으로 목표를 잡았다.
(이 데이터를 활용해서 여러 기능들을 추가하는것은 덤.)</p>
<h2 id="chess-data">Chess Data</h2>
<blockquote>
<p>모든 체스 데이터는 lichess.data에서 가져왔음. 오픈소스고 무료!</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/4hyoungsoo_/post/14feb75d-67c8-4f8d-8564-7fdc1ee3d6ad/image.png" alt="">
이번 포스트는 체스 오프닝 데이터를 처리하고 데이터베이스에 저장하는 포스팅을 해보겠다.</p>
<p><img src="https://velog.velcdn.com/images/4hyoungsoo_/post/a438b6b5-2a32-4470-8814-186e18f7c29a/image.png" alt="">
lichess에서 제공해주는 체스 오프닝 데이터는 5개의 tsv파일로 이루어져 있고</p>
<p><img src="https://velog.velcdn.com/images/4hyoungsoo_/post/a717b69a-4342-49e6-bf8b-424fba39dbd1/image.png" alt="">
dataframe으로 나타내면 이렇다.</p>
<pre><code class="language-python">import pandas as pd
data = pd.read_csv(fpath, sep=&quot;\t&quot;)

print(data)</code></pre>
<p>데이터 수집을 용이하게 하기 위해 5개의 tsv파일을 합쳐주자</p>
<pre><code class="language-python">data = pd.read_csv(fpath, sep=&quot;\t&quot;)

k = [&#39;b&#39;,&#39;c&#39;,&#39;d&#39;,&#39;e&#39;]

for i in k:
  fpath = &lt;filepath&gt;
  sub = pd.read_csv(fpath, sep=&#39;\t&#39;)

  data = pd.concat([data, sub])

data.to_csv(&lt;path&gt;/&lt;to&gt;/&lt;store&gt;, sep=&#39;\t&#39;)</code></pre>
<p>pandas를 활용하여 간단하게 tsv파일을 합칠 수 있다.</p>
<h2 id="chess-opening-pipeline">Chess opening Pipeline</h2>
<p>기본적으로 데이터를 저장하는 구조는 business process model의 구조를 활용 할 생각이다.</p>
<p><img src="https://velog.velcdn.com/images/4hyoungsoo_/post/4dd9d5a9-a24e-4969-b094-aaff3d5fdae9/image.png" alt="">
사진 출처 (<a href="https://www.researchgate.net/figure/Petri-net-model-that-captures-flexible-business-process-scenario_fig2_220830118">https://www.researchgate.net/figure/Petri-net-model-that-captures-flexible-business-process-scenario_fig2_220830118</a>)</p>
<blockquote>
<p>비지니스 프로세스 모델을 한줄로 설명하면 시작에서 완료까지 계획된 비즈니스 프로세스의 단계를 모델링하는 흐름도 메소드.
lichess에서 제공하는 오프닝 데이터의 기보를 살펴보면,
<img src="https://velog.velcdn.com/images/4hyoungsoo_/post/ea7dc109-39c2-46b4-a4fe-948bc310a6d3/image.png" alt="">
체스는 검은색, 흰색 플레이어가 번갈아가면서 한 수씩 두는 게임으로 </p>
</blockquote>
<ol>
<li>뒤에 Nh3는 흰색이 d5은 검은색이 둔 수이다. 비지니스 프로세스 모델처럼 시작과 끝이 있고 순차적인 데이터인걸 확인 할 수 있다.
한 줄의 데이터만 본다면 위의 프로세스 모델처럼 될 수 없지만, 여러개의 데이터를 조합하면 위의 모델을 도출할 수 있다.</li>
</ol>
<h3 id="feature-of-chess-opening-data">Feature of chess opening data</h3>
<p><img src="https://velog.velcdn.com/images/4hyoungsoo_/post/cda77617-99aa-4075-9d8f-f12eb1f95dff/image.png" alt=""></p>
<p>위의 사진은 체스 오프닝 데이터의 일부이다.</p>
<p>[&#39;1.&#39;, &#39;Nh3&#39;, &#39;d5&#39;, &#39;2.&#39;, &#39;g3&#39;, &#39;e5&#39;, &#39;3.&#39;, &#39;f4&#39;, &#39;Bxh3&#39;, &#39;4.&#39;, &#39;Bxh3&#39;, &#39;exf4&#39;] Amar Gambit
[&#39;1.&#39;, &#39;Nh3&#39;] Amar Opening
[&#39;1.&#39;, &#39;Nh3&#39;, &#39;d5&#39;, &#39;2.&#39;, &#39;g3&#39;, &#39;e5&#39;, &#39;3.&#39;, &#39;f4&#39;, &#39;Bxh3&#39;, &#39;4.&#39;, &#39;Bxh3&#39;, &#39;exf4&#39;, &#39;5.&#39;, &#39;O-O&#39;, &#39;fxg3&#39;, &#39;6.&#39;, &#39;hxg3&#39;] Amar Opening: Gent Gambit
[&#39;1.&#39;, &#39;Nh3&#39;, &#39;d5&#39;, &#39;2.&#39;, &#39;g3&#39;, &#39;e5&#39;, &#39;3.&#39;, &#39;f4&#39;] Amar Opening: Paris Gambit
[&#39;1.&#39;, &#39;e3&#39;, &#39;e5&#39;, &#39;2.&#39;, &#39;c4&#39;, &#39;d6&#39;, &#39;3.&#39;, &#39;Nc3&#39;, &#39;Nc6&#39;, &#39;4.&#39;, &#39;b3&#39;, &#39;Nf6&#39;] Amsterdam Attack
[&#39;1.&#39;, &#39;a3&#39;] Anderssen&#39;s Opening
[&#39;1.&#39;, &#39;a3&#39;, &#39;a5&#39;, &#39;2.&#39;, &#39;b4&#39;] Anderssen&#39;s Opening: Polish Gambit</p>
<p>데이터들의 한가지 공통점은 특정 부분을 기점으로 오프닝의 이름이 바뀐다는 것.</p>
<ul>
<li>[&#39;1.&#39;, &#39;Nh3&#39;] Amar Opening</li>
</ul>
<p>Nh3로 시작되는 오프닝은 Amar Opening이라는 이름이 붙고 위의 예시 데이터에서 Nh3로 시작되는 오프닝은</p>
<p>Amar Gambit, Amar Opening: Gent Gambit, Amar Opening: Paris Gambit이 존재한다.
그리고 이들 간 f4이후 분기가 나뉘고 Bxh3이후엔 완전히 나눠진다.</p>
<p>Nh3로 시작되는 다른 이름이 오프닝도 있지만 위의 예시처럼 특정 분기에서 나뉘어 진다는 특징이 있다.</p>
<h3 id="preprocessing-opening-data">PreProcessing Opening Data</h3>
<p>lichess에서 제공한 chess opening dataset에서 우리는 png, name, epd 컬럼을 추출하여 우리가 원하는 방식대로 변경하여 csv로 저장할 것이다.</p>
<pre><code class="language-python">#pipline.py

from .utils import *

class ChessOpeningPipeline:
    def data_preprocessing(self, fpath):
        return import_data_csv(fpath=fpath)

    def export_to_csv(self, fname, data):
      data.to_csv(f&#39;C:\\Users\\aaa57\\chess\\dist\\{fname}.csv&#39;)
      return

</code></pre>
<pre><code class="language-python">#utils.py
import pandas as pd


def import_data_csv(fpath, sep = &#39;\t&#39;):
  data = pd.read_csv(fpath, sep=sep)
  df = split_data(data)

  df = pd.DataFrame(df, columns=[&#39;pgn&#39;,&#39;name&#39;,&#39;epd&#39;])

  return df


def split_data(data):
  df = []
  for i in data.index:
    val = data.loc[i, &#39;pgn&#39;].split(&#39; &#39;)
    name = data.loc[i, &#39;name&#39;]
    epd = data.loc[i,&#39;epd&#39;]
    k = _revmove_number(val)
    df.append([k,name,epd])

  df.sort(key=lambda x: len(x[0]))

  return df


def _revmove_number(value):
  a = list(filter(None ,map(_is_number, value)))

  return a

def _is_number(value):
  if value.endswith(&#39;.&#39;):
    return 
  else:
    return value

</code></pre>
<pre><code class="language-python">
#data_processor.py
from .pipelines import ChessOpeningPipeline

class DataProcessor:
  def data_processor():
    k = ChessOpeningPipeline()
    return k</code></pre>
<p>간단한 코드 몇줄로 데이터를 정제할 수 있었는데, pipeline과 data_processor를 따로 정의한 이유는 후에 django에서 사용하기 위함.</p>
<pre><code>,pgn,name,epd
0,[&#39;Nh3&#39;],Amar Opening,rnbqkbnr/pppppppp/8/8/8/7N/PPPPPPPP/RNBQKB1R b KQkq -
1,[&#39;a3&#39;],Anderssen&#39;s Opening,rnbqkbnr/pppppppp/8/8/8/P7/1PPPPPPP/RNBQKBNR b KQkq -
2,[&#39;f3&#39;],Barnes Opening,rnbqkbnr/pppppppp/8/8/8/5P2/PPPPP1PP/RNBQKBNR b KQkq -
3,[&#39;h3&#39;],Clemenz Opening,rnbqkbnr/pppppppp/8/8/8/7P/PPPPPPP1/RNBQKBNR b KQkq -
4,[&#39;g4&#39;],Grob Opening,rnbqkbnr/pppppppp/8/8/6P1/8/PPPPPP1P/RNBQKBNR b KQkq -
5,[&#39;g3&#39;],Hungarian Opening,rnbqkbnr/pppppppp/8/8/8/6P1/PPPPPP1P/RNBQKBNR b KQkq -
6,[&#39;h4&#39;],Kádas Opening,rnbqkbnr/pppppppp/8/8/7P/8/PPPPPPP1/RNBQKBNR b KQkq -
7,[&#39;d3&#39;],Mieses Opening,rnbqkbnr/pppppppp/8/8/8/3P4/PPP1PPPP/RNBQKBNR b KQkq -
8,[&#39;b4&#39;],Polish Opening,rnbqkbnr/pppppppp/8/8/1P6/8/P1PPPPPP/RNBQKBNR b KQkq -
9,[&#39;c3&#39;],Saragossa Opening,rnbqkbnr/pppppppp/8/8/8/2P5/PP1PPPPP/RNBQKBNR b KQkq -
10,[&#39;Na3&#39;],Sodium Attack,rnbqkbnr/pppppppp/8/8/8/N7/PPPPPPPP/R1BQKBNR b KQkq -</code></pre><p>이제 체스 오프닝 데이터를 프로세스화 시기키위한 준비는 다 되었다.</p>
<p>다음 포스팅은 django orm과 database를 활용하여 이 데이터를 저장하고 쿼리를 하는 포스팅을 할 예정.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[HDFS 작동방식]]></title>
            <link>https://velog.io/@4hyoungsoo_/HDFS-%EC%9E%91%EB%8F%99%EB%B0%A9%EC%8B%9D</link>
            <guid>https://velog.io/@4hyoungsoo_/HDFS-%EC%9E%91%EB%8F%99%EB%B0%A9%EC%8B%9D</guid>
            <pubDate>Tue, 20 Dec 2022 06:53:07 GMT</pubDate>
            <description><![CDATA[<h2 id="hdfs">HDFS</h2>
<blockquote>
<p>빅데이터를 전체 클러스터에 분산해 안정적으로 저장하여 애플리케이션이 그 데이터를 신속하게 액세스해 분석할 수 있게함.</p>
</blockquote>
<ul>
<li><p>HDFS는 대용량 파일들을 다루기 위해 만들어짐.</p>
</li>
<li><p>대용량 파일들을 작은 조각으로 나누어 클러스터 전체에 걸쳐 분산시키는데 최적화되어있다.</p>
<ul>
<li>대용량 파일 즉 빅데이터를 &#39;데이터 블록&#39;으로 나눔.</li>
<li>기본값은 128MB 혹은 그 이하</li>
<li>대용량 파일을 블록으로 나눔으로써 더 이상 하드 드라이브의 용량에 제한되지 않게한다.</li>
</ul>
</li>
<li><p>HDFS는 이 대용량 파일을 분산해서 처리.</p>
</li>
<li><p>대용량 파일을 쪼개 여러 컴퓨터에 걸쳐 저장했다면 각 컴퓨터는 자기에게 저장된 데이터 블록을 동시에 처리할 수 있게된다.</p>
</li>
<li><p>데이터를 효율적으로 엑세스할 수 있도록 데이터 블록을 처리하는 컴퓨터가 해당 블록이 저장된 곳이랑 가까운 거리에 있도록 조정함.</p>
</li>
<li><p>단 하나의 블록만 저장하지 않는다.</p>
<ul>
<li>모든 블록마다 두 개 이상의 복사본을 저장.</li>
<li>어떤 컴퓨터가 다운되더라도 HDFS가 그 블록의 백업 복사본을 갖고 있는 다른 컴퓨터에서 정보를 불러올 수 있도록 하기 위함.</li>
</ul>
</li>
<li><p>HDFS는 클러스터의 수많은 컴퓨터에 걸쳐 분산되어 있고 실패 회복력과 큰 가능성이 있지만 결국에는 파일 시스템을 갖춘 거대한 하드 드라이브.</p>
</li>
</ul>
<h3 id="name-node">Name Node</h3>
<ul>
<li>어느 블록이 어디에 있는지를 추적.</li>
<li>파일의 이름과 HDFS 내의 가상 디렉터리 구조 등의 정보가 있고 그 파일과 관련된 모든 블록과 해당 복사본들이 어떤 노드에 저장되어 있는지를 기록.</li>
<li>어떤 게 수정되고 저장되는지 등의 정보가 Edit log에 기록됨.</li>
<li>모든 &#39;데이터 노드&#39;(Data Node)에 무엇이 있는지는 이름 노드에 기록되고 클라이언트 애플리케이션은 &#39;이름 노드&#39;(Name Node)에 쿼리해 어디로 가야할지 알아낸 다음 궁극적으로 그 &#39;데이터 노드&#39;에 엑세스함.</li>
</ul>
<h3 id="data-node">Data Node</h3>
<ul>
<li>실제 파일의 블록을 저장하고 있는 곳.</li>
<li>Name Node와 블록의 복사본을 잘 유지하기 위해 서로 소통함.</li>
</ul>
<h3 id="in-hdfs-read-file">In HDFS Read File</h3>
<ul>
<li>&#39;이름 노드&#39;에게 파일 A가 필요하다고 전송.</li>
<li>&#39;이름 노드&#39;는 파일 A는 이러이러한 &#39;데이터 노드&#39;의 요러요러한 블록들에 저장되어 있다고 알려줌.</li>
<li>클라이언트 애플리케이션은 해당 &#39;데이터 노드&#39;에 방문해 그 블록들을 가져와 파일 A를 구성.</li>
</ul>
<blockquote>
<p>&#39;이름 노드&#39;에게 그 파일이 어떤 &#39;데이터 노드&#39;의 어느 블록에 있는지 어떤 &#39;데이터 노드&#39;에 가는 게 가장 효율적인지 등을 물어보면 &#39;이름 노드&#39;가 어디 어디로 가야 한다고 알려준다는 개념</p>
</blockquote>
<h2 id="how-to-write-to-hdfs">How To Write To HDFS</h2>
<ul>
<li>클라이언트 애플리케이션이 HDFS에 새 파일을 만들려고 할 때 먼저 블록의 위치를 추적하는 &#39;이름 노드&#39;에게 요청.</li>
<li>&#39;이름 노드&#39;는 새 파일 항목을 확인하고 그 블록의 위치를 정한 후에 클라이언트에게 어느 &#39;데이터 노드&#39;에 가서 저장하라고 알려줌.</li>
<li>클라이언트는 정해진 &#39;데이터 노드&#39;에게 가서 파일을 건네줌.</li>
<li>그 &#39;데이터 노드&#39;는 주변의 다른 &#39;데이터 노드&#39;에 복사본을 전달하고 또 전달.</li>
</ul>
<blockquote>
<p>&#39;이름 노드&#39;에서 전달받은 정보를 클라이언트가 &#39;데이터 노드&#39;에게 전달하고 그 &#39;데이터 노드&#39;는 &#39;데이터 노드&#39;끼리 전달. 그리고 데이터가 저장되면 잘 받았다는 신호를 클라이언트를 통해 &#39;이름 노드&#39;로 보냄. 그러면 &#39;이름 노드&#39;는 새로운 파일의 블록과 복사본의 위치를 기억함.</p>
</blockquote>
<ul>
<li>&#39;이름 노드&#39;는 그 파일이 존재하며 여러 &#39;데이터 노드&#39;에 걸쳐 복제되어 저장되었음을 기록.</li>
</ul>
<h2 id="when-name-node-is-unavailable">When Name Node is Unavailable</h2>
<ul>
<li><p>메타데이터를 계속 백업.</p>
</li>
<li><p>이차적 이름 노드를 운영.</p>
<ul>
<li>&#39;동적 백업&#39;(hot backup)이 아님. 동시에 운영하지 않기 때문.</li>
<li>&#39;주 이름 노드&#39;의 편집 로그 복사본을 유지하는것.</li>
</ul>
</li>
<li><p>HDFS 연합(Federation).</p>
<ul>
<li>HDFS는 많은 수의 작은 파일보다는 대용량 파일을 다루는데 최적화돼 있음.</li>
<li>이름 노드는 한계점에 다다랐을 때, HDFS 연합은 HDFS 파일 구조 내에 &#39;명칭 공간 볼륨&#39;(namespace volume)이라고 부르는 서브디렉터리마다 분리된 이름 노드를 지정함.</li>
<li>그러면 각 볼륨마다 데이터 파일을 읽거나 쓸 때 어떤 이름 노드와 얘기해야 하는지 알 수 있음.</li>
</ul>
</li>
<li><p>&#39;HDFS 고가용성(High Availability)&#39;을 사용해 &#39;동적 예비 이름 노드&#39;를 운영.</p>
<ul>
<li>공유 편집 로그를 활용하여 이름 노드가 HDFS가 아닌 다른 안전한 공유 저장소에 편집 로그를 작성.</li>
<li>주 이름 노드가 다운되면 &#39;동적 예비 이름 노드&#39;가 바로 업무를 이어받음.</li>
<li>Zookeeper가 어떤 이름 노드를 사용한다고 하면 다른 이름 노드의 전원을 완전히 차단해버려 어떤 클라이언트도 이 노드와 소통하지 못하게 함.<blockquote>
<p>HDFS 고가용성을 사용할 때 예로 두 개의 이름 노드가 동시에 작동할 수도 있음. 쓰기 요청을 받을 때 한 이름 노드는 그 데이터가 어디에 있는지 알고 다른 노드는 모를 수 있는 문제가 생길 수 있음.</p>
</blockquote>
</li>
</ul>
</li>
</ul>
<h2 id="how-to-use-hdfs">How To Use HDFS</h2>
<ul>
<li>유저 인터페이스를 사용.</li>
<li>명령줄 인터페이스.</li>
<li>HTTP.<ul>
<li>직접적으로 하거나 프락시 서버를 활용.</li>
<li>프락시 서버는 HDFS 머신과 클라이언트 사이에 위치.</li>
<li>데이터를 분석하기 위해 스크립트를 작성하거나 애플리케이션 개발을 위해 이 프락시 서버에 웹 인터페이스를 구성.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[MYSQL Hadoop 통합하기]]></title>
            <link>https://velog.io/@4hyoungsoo_/MYSQL-Hadoop-%ED%86%B5%ED%95%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@4hyoungsoo_/MYSQL-Hadoop-%ED%86%B5%ED%95%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Fri, 16 Dec 2022 16:17:50 GMT</pubDate>
            <description><![CDATA[<h2 id="sqoop">Sqoop</h2>
<blockquote>
<p>Hive는 Hadoop 클러스터를 관계형 데이터베이스처럼 사용하지만 실제로 데이터베이스를 갖는 것은 아니었다. 그러나 만약 MySQL과 같은 진짜 관계형 데이터베이스를 갖고 있고 Hadoop 클러스터에 데이터를 불러오거나 내보내고 싶을 수도 있을 때 Sqoop을 활용하여 할 수 있다.</p>
</blockquote>
<h4 id="mysql">MYSQL</h4>
<ul>
<li>거대한 하드 드라이브에 연결되는 하나의 서버에 설치.</li>
<li>클러스터에 분산되지 않고 모든 것이 로컬에 있으므로 온라인 처리 프로세싱(OLTP)에 적절.</li>
<li>데이터베이스에서 빠르게 결과를 구해야 한다면 MySQL 같은 도구가 적절</li>
</ul>
<h4 id="sqoop-1">Sqoop</h4>
<ul>
<li>SQL과 Hadoop을 합친 이름.</li>
<li>대용량 데이터 세트를 Hadoop 클러스터에 가져오거나 내보내고 관리한다.<ul>
<li>MapReduce 작업을 통해 가능 함.</li>
<li>데이터베이스를 Hadoop으로 내보내려고 하면 Sqoop은 내부적으로 여러 매퍼를 작동한다.(데이터를 한 곳에서 다른 곳으로 옮기는 일이니 매퍼만 사용)</li>
<li>매퍼들은 Hadoop 클러스터의 HDFS 클러스터와 소통하며 HDFS에 거대한 테이블 생성한다.</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/4hyoungsoo_/post/1a75a98f-bc77-4c9a-a2c3-81699e7781cf/image.png" alt=""></p>
<h6><center>Apache OverView (https://blogs.apache.org/sqoop/entry/apache_sqoop_overview)
</center></h6>

<ul>
<li>Mapper에서 HDFS로 들어가는 과정은 병렬적으로 처리됨.</li>
<li>각 Mapper는 같은 호스트에 있는 HDFS의 블록들과 개별적으로 소통하고 있으니 병목현상이 일어나지 않음.</li>
</ul>
<h4 id="sql-to-hdfs">SQL to HDFS</h4>
<pre><code>sqoop import --connect jdbc:mysql://&lt;hostname&gt;/&lt;databasename&gt; -- driver com.mysql.jdbc.Driver --table &lt;tablename&gt;</code></pre><ul>
<li>sqoop은 명령창에서만 작동됨.<ul>
<li>{sqoop import}는 데이터를 클러스터로 가져온다는 뜻.</li>
<li>&#39;driver&#39;를 명시해서 문제를 사전에 방지.</li>
</ul>
</li>
</ul>
<h4 id="sql-to-hive">SQL to Hive</h4>
<ul>
<li>파일을 HDFS 클러스터로 옮기는 중간 단계를 건너 뛰고 Hive 테이블을 만드는 것.</li>
</ul>
<pre><code>sqoop import --connect jdbc:mysql://&lt;hostname&gt;/&lt;databasename&gt; -- driver com.mysql.jdbc.Driver --table &lt;tablename&gt; --hive-import</code></pre><ul>
<li>끝에 &#39;--hive-import&#39;라는 매개 변수를 추가하기만 하면 된다.</li>
</ul>
<h4 id="incremental-import">Incremental import</h4>
<ul>
<li>데이터베이스를 불러올 때 순차 번호나 타임스탬프를 사용해 어디까지 가져왔는지 기억할 수 있음.</li>
<li>&#39;--check-column&#39;이란 매개 변수는 타임스탬프나 순차 번호 등을 가진 열(column).</li>
<li>&#39;--last-value&#39;는 열(column)의 값이 지정된 값보다 클 때만 데이터를 가져오겠다는 뜻</li>
<li>이걸 사용해 데이터베이스를 불러올 때 순차 번호나 타임스탬프를 사용해어디까지 가져왔는지 기억할 수 있다.</li>
</ul>
<h4 id="hive-to-sql">Hive to SQL</h4>
<pre><code>sqoop export --connect jdbc:mysql://&lt;hostname&gt;/&lt;databasename&gt; -- driver com.mysql.jdbc.Driver --table &lt;tablename&gt; --export-dir /&lt;where&gt;/&lt;is&gt;/&lt;hive data&gt; --input-fields-terminated-by &#39;\0001&#39;</code></pre><ul>
<li>&#39;import&#39; 대신 {sqoop export}라고 입력하고 연결하려는 데이터베이스를 지정</li>
<li>&#39;-m 1&#39;은 하나의 매퍼만 사용한다는 뜻.</li>
<li>데이터를 저장할 MySQL의 테이블을 지정한다 이때 Sqoop이 테이블을 따로 만들지 않도록 그 테이블이 존재하는지 확인해야 한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[HIVE 작동방식]]></title>
            <link>https://velog.io/@4hyoungsoo_/HIVE-%EC%9E%91%EB%8F%99%EB%B0%A9%EC%8B%9D</link>
            <guid>https://velog.io/@4hyoungsoo_/HIVE-%EC%9E%91%EB%8F%99%EB%B0%A9%EC%8B%9D</guid>
            <pubDate>Fri, 16 Dec 2022 13:50:44 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/4hyoungsoo_/post/7b610710-56ef-4882-9b1e-16d69a2b61aa/image.png" alt=""></p>
<h2 id="shcema-on-read">Shcema on Read</h2>
<ul>
<li><p>관계형 데이터베이스에서는 Schema on Write 개념을 사용한다.</p>
<ul>
<li>데이터베이스에 데이터를 입력하기전에 스키마를 정의.</li>
<li>데이터를 디스크에 저장할 때 이 스키마대로 시행.</li>
</ul>
</li>
<li><p>Hive는 구조화되지 않은 데이터를 가져와서 읽는 순간에 스키마를 적용한다.</p>
<ul>
<li>ex) 데이터는 탭으로 구분된 텍스트 파일이지만 실제로 구조화되지는 않은 상태</li>
<li>데이터가 뭘 나타내는지에 대한 정보가 없다. 하지만 Hive는 그 구조화되지 않은 데이터와 연관된 실제 스키마 데이터인 메타스토어를 가지고 있음.</li>
<li>텍스트 파일을 어떻게 해석할지 알려준다.</li>
</ul>
</li>
</ul>
<pre><code class="language-sql">CREATE TABLE ratings (
    userID INT,
    movieID INT,
    rating INT,
    time INT)
ROW FORMAT DELIMETED
FIELDS TERMINATED BY &#39;\t&#39;
STORED AS TEXTFILE

LOAD DATA LOCAL INPAHT &#39;&lt;PATH the data file&gt;&#39;
OVERWRITE INTO TABLE ratings</code></pre>
<ul>
<li>&#39;CREATE TABLE ratings&#39;라는 명령어를 입력하고 다양한 필드 이름과 유형을 지정.</li>
<li>데이터가 디스크에 어떻게 구조화되는지 지정.</li>
<li>행은 탭 구분 기호로 나눠져 있고 텍스트 파일로 저장.</li>
</ul>
<blockquote>
<p>Hive는 구조화된 관계형 데이터베이스를 만드는 게 아님. 클러스터에 있는 기존의 데이터를 읽을 때 스키마를 적용하는 것. &#39;LOAD DATA&#39; 명령어를 사용하면 데이터를 분산 파일 시스템에서 Hive로 가져오고 그 데이터에 대한 소유권을 갖고 관리한다.</p>
</blockquote>
<h2 id="managed-table-vs-external-table">Managed TABLE vs External TABLE</h2>
<ul>
<li>누가 데이터를 소유하고 삭제하는가의 차이.</li>
</ul>
<ul>
<li>Managed TABLE<ul>
<li>Hive로 가져온 데이터는 Hive의 소유가 되는 것.</li>
<li>&#39;DROP TABLE&#39; 명령어를 사용하면 그 데이터는 삭제.</li>
</ul>
</li>
<li>External TABLE<ul>
<li>External TABLE의 의미는 Hive가 소유권을 갖지 않는다는 겁</li>
<li>Hive 외부의 다른 시스템과 공유해야 할 때.</li>
<li>&#39;CREATE EXTERNAL TABLE&#39;로 사용가능.</li>
<li>이 데이터에 Hive를 사용하지만 소유하지는 않는다고 하는 것.</li>
<li>&#39;DROP&#39;하면 메타데이터만 버리고 이 데이터는 삭제되지 않음.</li>
</ul>
</li>
</ul>
<h2 id="partitioning">Partitioning</h2>
<ul>
<li>만약 대용량 데이터 세트 중의 일정 부분에만 쿼리한다면 최적화하는데 파티션이 중요한 역할을 함.</li>
</ul>
<pre><code class="language-sql">CREATE TABLE customers(
    name STRING,
    address STRUCT&lt;street:STRING, city:STRING, state:STRING, zip:INT&gt;)

PARTITIONED BY (country STRING);</code></pre>
<ul>
<li>customers 데이터베이스 안에 name, address속성이 있음.</li>
<li>PARTITIONED BY (country STRING);<ul>
<li>country를 하나의 열로 취급.</li>
</ul>
</li>
<li>전체 데이터베이스를 검색하지 않아도 되니 많은 시간을 절약할 수 있음.</li>
</ul>
<h4 id="struct">STRUCT</h4>
<ul>
<li>&#39;address&#39;를 보면 &#39;street:STRING&#39;과&#39;city:STRING&#39;,&#39;state:STRING&#39;, &#39;zip:INT&#39;를 포함.<ul>
<li>Hive 데이터베이스에 구조화 데이터를 저장할 수 있음.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Hive]]></title>
            <link>https://velog.io/@4hyoungsoo_/Hive</link>
            <guid>https://velog.io/@4hyoungsoo_/Hive</guid>
            <pubDate>Fri, 16 Dec 2022 13:15:56 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/4hyoungsoo_/post/1e3d93a5-ba8a-41a3-9fbb-394375afb1dd/image.png" alt=""></p>
<h2 id="hive">Hive</h2>
<blockquote>
<p>Hive 기술을 통해 hadoop 클러스터를 관계형 데이터베이스처럼 사용할 수 있다.</p>
</blockquote>
<ul>
<li>SQL을 사용해 Hadoop 클러스터에 걸쳐있는 데이터를 쿼리하는 간단하고 강력한 도구.(구조화된 쿼리 언어)</li>
<li>HDFS 클러스터 전체에 걸쳐 저장된 데이터에 표준 SQL 쿼리를 실행.<ul>
<li>SQL을 MapReduce나 TEZ 명령어로 번역해서 작동.</li>
<li>YARN 클러스터 관리자 위에서 실행.</li>
<li>Hive는 SQL 쿼리를 매퍼와 리듀서로 분해하고 클러스터 전체에 걸쳐 어떻게 실행할지를 알아낸다.<blockquote>
<p>사용자의 관점에서는 데이터 웨어하우스를 사용하는 것처럼 SQL 데이터베이스에 쿼리하는 것과 같다.</p>
</blockquote>
</li>
</ul>
</li>
</ul>
<h2 id="hiveql">HiveQL</h2>
<ul>
<li>MySQL 구문과 굉장히 비슷.</li>
<li>SQL에서 할 수 있는 모든 것을 HiveQL에서 할 수 있다.</li>
<li>HiveQL은 대화형 명령 프롬프트를 사용.<ul>
<li>&#39;SELECT&#39; 명령어 등을 사용해 일반 데이터베이스에 하듯 사용가능.</li>
</ul>
</li>
<li>결과가 즉각적으로 나오진 않겠지만 상식적인 시간 내에 결과를 얻을 것이고 단일 데이터베이스 인스턴스에서보다 훨씬 큰 데이터를 처리할 수 있다.</li>
<li>실시간 처리 등의 작업에는 적합하지 않을 수 있지만 대용량 데이터 세트에 분석 쿼리를 하려는 것이라면 Hive가 제격.</li>
</ul>
<h2 id="hive-weakpoint">Hive weakpoint</h2>
<ul>
<li>고 처리량, 저 대기 시간을 원한다면 좋은 선택이 아님.<ul>
<li>SQL 명령어를 MapReduce로 번역을 해야 하기 때문에 시간이 더 걸리기 때문.</li>
</ul>
</li>
<li>비정규화 데이터를 사용.<ul>
<li>관계형 데이터베이스인 것처럼 쿼리할 수 있지만 실제론 모든 것이 비정규화되어 있고 연결된 별도의 테이블이나 키 등을 갖고 있지 않는다.</li>
<li>업데이트나, 삽입, 삭제 등을 해도 기록되지 않는다. (실제 데이터베이스가 아니기 때문. 거대한 하나의 텍스트 파일)</li>
</ul>
</li>
<li>잡한 쿼리를 해야 한다면 Pig나 Spark가 좀 더 적합.<ul>
<li>(다만 나중에 VIEW를 통해 연계 사용 가능.)</li>
</ul>
</li>
</ul>
<h2 id="hive-view">Hive VIEW</h2>
<ul>
<li>어떤 쿼리의 결과를 &#39;VIEW&#39;에 저장하고 그 &#39;VIEW&#39;를 다음 쿼리의 테이블로 사용할 수 있는 아주 유용한 기능.</li>
<li>복잡한 쿼리를 개별 쿼리로 분할해 이 &#39;VIEW&#39;를 점점 발전시키며 층층이 쌓아 구축할 수 있다.</li>
</ul>
<h2 id="hive-example">Hive example</h2>
<pre><code class="language-sql">CREATE VIEW IF NOT EXISTS topMovieIDs AS 
SELECT movieID, count(movieID) as ratingCount
FROM ratings
GROUP BY movieID
ORDER BY ratingCount DESC;

SELECT n.name ratingCount
FROM topMovieIDs t JOIN movie_names n ON t.movieID * n.movie_ID;</code></pre>
<ul>
<li>기본적으로 관계형 데이터베이스 언어 (MYSQL)의 문법과 별반 차이가 없다.</li>
<li>CREATE VIEW<ul>
<li>위에서 설명한 Hive의 특징으로 VIEW를 만들어 다음 쿼리로 넘길 수 있다.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Hadoop 주요 구성 요소(3)]]></title>
            <link>https://velog.io/@4hyoungsoo_/Hadoop-%EC%A3%BC%EC%9A%94-%EA%B5%AC%EC%84%B1-%EC%9A%94%EC%86%8C3</link>
            <guid>https://velog.io/@4hyoungsoo_/Hadoop-%EC%A3%BC%EC%9A%94-%EA%B5%AC%EC%84%B1-%EC%9A%94%EC%86%8C3</guid>
            <pubDate>Fri, 16 Dec 2022 07:45:55 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/4hyoungsoo_/post/c6b2eaeb-97d4-4e01-a1bf-0a29a0c7ac9b/image.png" alt=""></p>
<h2 id="zookeeper">Zookeeper</h2>
<ul>
<li>Zookeeper는 클러스터의 모든 것을 조직화하는 기술.</li>
<li>어떤 노드가 살아있는지 추적할 수 있고 여러 애플리케이션이 사용하는 클러스터의 공유 상태를 안정적으로 확인할 수 있다.</li>
<li>많은 애플리케이션이 Zookeeper에 의존.<ul>
<li>그래서 어떤 노드가 다운되더라도 일관성 있고 안정적인 성능을 온 클러스터에 걸쳐 유지할 수 있게함.</li>
</ul>
</li>
<li>어떤 것이 마스터 노드이며 어떤 노드가 살아있고 다운되어 있는지 추적하는데 사용할 수 있다.</li>
</ul>
<h2 id="sqoop">Sqoop</h2>
<ul>
<li>Sqoop은 Hadoop의 데이터베이스를 관계형 데이터베이스로 엮어낸다.</li>
<li>ODBC나 JDBC로 소통 가능한 데이터는 Sqoop을 통해 HDFS의 파일로 변형할 수 있다.</li>
<li>Sqoop은 레거시 데이터베이스와 Hadoop을 잇는 연결 장치.</li>
</ul>
<h2 id="flume">FLUME</h2>
<ul>
<li>FLUME을 가지고 대규모 웹로그를 안정적으로 클러스터에 불러올 수 있다.<blockquote>
<p>예로 웹 서버 여러 개를 가지고 있다고 합시다 FLUME은 실시간으로 웹 서버의 웹로그를 감시하고 클러스터에 게시해 STORM이나 Spark Streaming을 사용해 처리한다.</p>
</blockquote>
</li>
</ul>
<h2 id="kafka">Kafka</h2>
<ul>
<li>Kafka도 데이터 수집을 하지만 좀 더 포괄적으로 사용된다.</li>
<li>PC 혹은 웹 서버 클러스터에서 모든 종류의 데이터를 수집해 Hadoop 클러스터로 보낸다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Hadoop 주요 구성 요소(2)]]></title>
            <link>https://velog.io/@4hyoungsoo_/Hadoop-%EC%83%9D%ED%83%9C%EA%B3%84-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B02</link>
            <guid>https://velog.io/@4hyoungsoo_/Hadoop-%EC%83%9D%ED%83%9C%EA%B3%84-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B02</guid>
            <pubDate>Fri, 16 Dec 2022 07:40:03 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/4hyoungsoo_/post/c6b2eaeb-97d4-4e01-a1bf-0a29a0c7ac9b/image.png" alt=""></p>
<h2 id="mesos">Mesos</h2>
<ul>
<li>클러스터의 리소스를 관리하는 또 하나의 방법.</li>
<li>YARN과 협업이 가능하다.</li>
</ul>
<h2 id="spark">Spark</h2>
<ul>
<li>Hadoop 생태계에서 가장 흥미로운 기술.</li>
<li>Spark는 YARN이나 Mesos중 어느 쪽을 기반으로 하든 데이터에 쿼리를 실행할 수 있음.</li>
<li>Pyhon, Java, Scala를 사용해 스크립트를 작성.</li>
<li>클러스터의 데이터를 신속하고 효율적으로 처리가 가능하다.</li>
<li>많은 다양성을 갖고있음.<ul>
<li>클러스터에 걸친 정보로 머신 러닝을 수행하는 SQL쿼리.</li>
<li>실시간으로 스트리밍되는 데이터를 처리하는 등.</li>
</ul>
</li>
</ul>
<h2 id="tez">TEZ</h2>
<ul>
<li>방향성 비사이클 그래프<ul>
<li>TEZ는 MapReduce의 일을 할 때 더 유리함.</li>
<li>쿼리실행에 더 효율적인 계획을 세우기 때문.</li>
<li>Hive와 함께 사용하면 성능을 극대화 시킬 수 있음.</li>
</ul>
</li>
</ul>
<h2 id="hbase">HBASE</h2>
<ul>
<li>HBASE는 클러스터의 데이터를 트랜잭션 플랫폼으로 노출하는 역할을 하며 NoSQL 데이터베이스라고 불린다.</li>
<li>기둥형 데이터 스토어<ul>
<li>단위 시간당 실행되는 트랜잭션의 수가 큰 아주 빠른 데이터베이스</li>
<li>데이터를 웹 애플리케이션이나 웹사이트에 노출시켜 OLTP 트랜잭션을 하는데 적합하다.</li>
</ul>
</li>
<li>HBASE는 클러스터에 저장된 데이터를 노출시킨다. </li>
<li>데이터는 Spark나 MapReduce 등에 의해 전환되었을 수도 있고 후에 그 결과를 다른 시스템에 노출시킬 빠른 방법을 제공한다.</li>
</ul>
<h2 id="apache-storm">Apache STORM</h2>
<ul>
<li>STORM은 스트리밍 데이터를 처리하는 방식.</li>
<li>센서나 웹로그로부터 데이터를 스트리밍 한다면 STORM이나 &#39;Spark Streaming&#39;을 통해 실시간으로 처리할 수 있다.</li>
<li>일괄로 처리할 필요가 없음.</li>
<li>데이터가 실시간으로 입력됨에 따라 실시간으로 &#39;기계 학습&#39;을 업데이트하거나 데이터를 데이터베이스에 저장할 수 있다.</li>
</ul>
<h2 id="oozie">OOZIE</h2>
<ul>
<li>OOZIE는 일정에 따라 작업을 순차적으로 진행할 수 있도록 스케줄링.<blockquote>
<p>예를 들어 데이터를 Hive에 불러와서 Pig를 통해 통합하고 Spark를 통해 쿼리한 후에 결과를 HBASE로 변환시킨다고 하면 OOZIE가 이 모든 것을 관리해 안정적이고 일관성 있게 실행할 수 있다.</p>
</blockquote>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Hadoop 주요 구성 요소]]></title>
            <link>https://velog.io/@4hyoungsoo_/Hadoop-%EC%A3%BC%EC%9A%94-%EA%B5%AC%EC%84%B1-%EC%9A%94%EC%86%8C</link>
            <guid>https://velog.io/@4hyoungsoo_/Hadoop-%EC%A3%BC%EC%9A%94-%EA%B5%AC%EC%84%B1-%EC%9A%94%EC%86%8C</guid>
            <pubDate>Fri, 16 Dec 2022 07:10:19 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/4hyoungsoo_/post/6d4c1e6b-3863-479c-8411-5e12cb7b3b4b/image.png" alt="https://www.softwaretestingclass.com/introduction-to-hadoop-architecture-and-components/"></p>
<h2 id="hdfs">HDFS</h2>
<ul>
<li>Hadoop 분산 파일 시스템</li>
<li>빅데이터를 클러스터의 컴퓨터들에 분산 저장하는 시스템.</li>
<li>데이터의 여분 복사본까지 만들어 데이터의 손실을 자동을 회복함.</li>
<li>Hadoop의 데이터 저장 부분.</li>
</ul>
<h2 id="yarn">YARN</h2>
<ul>
<li>&#39;Yet Another Resource Negotiator&#39;의 약어이며 &#39;또 다른 리소스 교섭자&#39;라는 뜻.</li>
<li>YARN은 Hadoop의 데이터 처리 부분.</li>
<li>컴퓨터 클러스터의 리소스를 관리하는 시스템.<ul>
<li>누가 작업을 언제 실행하고 어떤 노드가 추가 작업을 할 수 있고 누구는 할 수 없고 등을 결정.</li>
</ul>
</li>
</ul>
<h2 id="mapreduce">MapReduce</h2>
<ul>
<li>데이터를 클러스터 전체에 걸쳐 처리하도록 하는 프로그래밍 모델.</li>
<li>Mapper와 Reducer로 구성되어 있어 프로그램을 사용할 때 사용하는 두 개의 구분된 함수<ul>
<li>Mapper는 클러스터에 분산돼있는 데이터를 효율적으로 동시에 변경할 수 있음.</li>
<li>Reducer는 그 데이터를 집계함.</li>
</ul>
</li>
</ul>
<h2 id="pig">Pig</h2>
<ul>
<li>Pig는 고수준의 API&#39;로써 많은 경우 SQL과 비슷한 간단한 스크립트를 작성해 쿼리를 연결하고 복잡한 답을 구할 수 있다.</li>
<li>프로그래밍 언어를 사용하지 않아도 사용 가능.</li>
<li>Pig는 작성된 스크립트를 MapReduce가 읽을 수 있도록 번역하고 MapReduce는 다시 YARN과 HDFS에게 데이터를 처리하고 원하는 답을 가져오게한다.</li>
<li>Pig는 MapReduce위에 있는 고수준 스크립팅 언어.</li>
</ul>
<h2 id="hive">Hive</h2>
<ul>
<li>MapReduce위에 구축돼 Pig처럼 작동하지만 더 SQL 데이터베이스 역할을 수행함.</li>
<li>셸 클라이언트나 ODBC(Open Database Connectivity) 등을 통해 데이터베이스에 접속할 수 있으며 Hadoop 클러스터에 저장돼있는 데이터가 내부적으로는 관계형 데이터베이스가 아님에도 불구하고 SQL로 쿼리한다</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Hadoop 생태계 이해하기 ]]></title>
            <link>https://velog.io/@4hyoungsoo_/Hadoop-%EC%83%9D%ED%83%9C%EA%B3%84-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@4hyoungsoo_/Hadoop-%EC%83%9D%ED%83%9C%EA%B3%84-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0</guid>
            <pubDate>Fri, 16 Dec 2022 06:55:59 GMT</pubDate>
            <description><![CDATA[<h1 id="what-is-hadoop">What is Hadoop</h1>
<p>Hadoop 플랫폼의 주요 벤더인 Hortonworks는 하둡을 이렇게 정의.</p>
<blockquote>
<p>범용 하드웨어로 구축된 컴퓨터 클러스터의 아주 방대한 데이터 세트틀 분산해 저장하고 처리하는 <strong>오픈 소스</strong> 소프트웨어 플랫폼</p>
</blockquote>
<h3 id="hadoop">Hadoop</h3>
<ul>
<li>오픈 소스 </li>
<li>한대의 PC가 아닌 컴퓨터 클러스터에서 작동하는 소프트웨어 묶음<ul>
<li>Hadoop은 어느 데이터 센터에서 작동중인 컴퓨터 클러스터 전체에서 실행되도록 설계됨.</li>
<li>즉 Hadoop은 다수의 PC를 활용해 빅데이터를 다룬다.</li>
</ul>
</li>
</ul>
<ul>
<li>분산저장<ul>
<li>분산 저장은 Hadoop이 제공하는 주 기능.</li>
<li>한 개의 하드 드라이브에 국한되지 않는다.</li>
<li>빅데이터(1TB)를 처리할 때 클러스터에 컴퓨터를 더하기만 하면 그 컴퓨터는 하드 드라이브가 데이터 저장소의 일부가 됨.</li>
<li>Hadoop은 클러스터의 모든 하드 드라이브에 걸쳐 분산돼 있는 모든 데이터를 단일 파일 시스템으로 보여줌.</li>
</ul>
</li>
</ul>
<ul>
<li>데이터의 여분 제공<ul>
<li>Hadoop은 클러스터의 컴퓨터 중 하나가 사용 불가 상태에 놓여있어도 이런 상황을 데이터 백업 복사본을 클러스터의 다른 컴퓨터에도 보관하기 때문에 자동으로 소실된 데이터를 복구할 수 있음.</li>
</ul>
</li>
</ul>
<ul>
<li>분산 처리<ul>
<li>Hadoop은 데이터를 다른 양식으로 전환하거나 다른 시스템으로 전송할 때 혹은 집계해야 할 때 모든 작업을 병렬로 처리한다.</li>
<li>클러스터 내 모든 컴퓨터 CPU에게 이 작업을 분배하여 동시에 처리.</li>
<li>많은 데이터를 신속히 처리할 수 있음.</li>
<li>처리할 수 없다면 컴퓨터를 추가하면 가능.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>