<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>etl-windy</title>
    <link>https://etlwindy.tistory.com/</link>
    <description>etl-windy</description>
    <language>ko</language>
    <pubDate>Mon, 6 Apr 2026 04:34:45 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>killog</managingEditor>
    <image>
      <title>etl-windy</title>
      <url>https://tistory1.daumcdn.net/tistory/4968178/attach/a8836d2be011437783187b8d16089237</url>
      <link>https://etlwindy.tistory.com</link>
    </image>
    <item>
      <title>spark 집계 방식 설명</title>
      <link>https://etlwindy.tistory.com/25</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/28240706/explain-the-aggregate-functionality-in-spark-with-python-and-scala&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stackoverflow.com/questions/28240706/explain-the-aggregate-functionality-in-spark-with-python-and-scala&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1642352977757&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Explain the aggregate functionality in Spark (with Python and Scala)&quot; data-og-description=&quot;I am looking for some better explanation of the aggregate functionality that is available via spark in python. The example I have is as follows (using pyspark from Spark 1.2.0 version) sc.paral...&quot; data-og-host=&quot;stackoverflow.com&quot; data-og-source-url=&quot;https://stackoverflow.com/questions/28240706/explain-the-aggregate-functionality-in-spark-with-python-and-scala&quot; data-og-url=&quot;https://stackoverflow.com/questions/28240706/explain-the-aggregate-functionality-in-spark-with-python-and-scala&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cLR5lk/hyM6z1S0bB/4e8gOKFKUV32hE9hMgepT0/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/28240706/explain-the-aggregate-functionality-in-spark-with-python-and-scala&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://stackoverflow.com/questions/28240706/explain-the-aggregate-functionality-in-spark-with-python-and-scala&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cLR5lk/hyM6z1S0bB/4e8gOKFKUV32hE9hMgepT0/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Explain the aggregate functionality in Spark (with Python and Scala)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;I am looking for some better explanation of the aggregate functionality that is available via spark in python. The example I have is as follows (using pyspark from Spark 1.2.0 version) sc.paral...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;stackoverflow.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://whereami80.tistory.com/105&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://whereami80.tistory.com/105&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1642352982875&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;SPARK aggregate() 함수 설명 및 진행 과정&quot; data-og-description=&quot;책에서 봤을 때 내부 과정이 이해가 안됬음. 그래서 찾아봤더니 이런 심오한 .... 일단 이 함수를 이해하는데 기억해야 할 점은 2가지 ... 1) rdd 데이터 타입과 action 결과 타입이 다를경우 사용한다&quot; data-og-host=&quot;whereami80.tistory.com&quot; data-og-source-url=&quot;https://whereami80.tistory.com/105&quot; data-og-url=&quot;https://whereami80.tistory.com/105&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/N9s6K/hyM6DpHjOW/2F1qS7Z0SM60AS7n55ZK80/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/fNj6l/hyM78VUlKX/G8fD7rPfs3h6zP7hHkEa30/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot;&gt;&lt;a href=&quot;https://whereami80.tistory.com/105&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://whereami80.tistory.com/105&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/N9s6K/hyM6DpHjOW/2F1qS7Z0SM60AS7n55ZK80/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/fNj6l/hyM78VUlKX/G8fD7rPfs3h6zP7hHkEa30/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;SPARK aggregate() 함수 설명 및 진행 과정&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;책에서 봤을 때 내부 과정이 이해가 안됬음. 그래서 찾아봤더니 이런 심오한 .... 일단 이 함수를 이해하는데 기억해야 할 점은 2가지 ... 1) rdd 데이터 타입과 action 결과 타입이 다를경우 사용한다&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;whereami80.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.quora.com/How-does-the-aggregate-function-works-in-Apache-spark-using-Python&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.quora.com/How-does-the-aggregate-function-works-in-Apache-spark-using-Python&lt;/a&gt;&lt;/p&gt;</description>
      <category>spark</category>
      <author>killog</author>
      <guid isPermaLink="true">https://etlwindy.tistory.com/25</guid>
      <comments>https://etlwindy.tistory.com/25#entry25comment</comments>
      <pubDate>Mon, 17 Jan 2022 02:09:54 +0900</pubDate>
    </item>
    <item>
      <title>패스트 캠퍼스 엘라스틱서치 PART04. 부속 프로세싱 - 이미지 처리 기술과 검색 기술의 융합</title>
      <link>https://etlwindy.tistory.com/24</link>
      <description>&lt;h1&gt;04. 부속 프로세싱 - 이미지 처리 기술과 검색 기술의 융합&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;intro&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;검색 엔진, 그리고 정보처리엔진 이런 것에는 문자나 텍스트만으로 국한될 필요는 없다. 실제로 우리가 디지털화할 수 있는 모든 데이터 , 즉 이미지 데이터 , 비디오, 동영상, 3D 이미지, 그리고 속성들 그리고 들릴 수 있는 소리, 가상현실 등등 여러가지 데이터들의 의미를 처리할 수 있다.&lt;/li&gt;
&lt;li&gt;검색 엔진은 문자뿐만아니라 이미지 등 여러가지 있는 뜻을 추출해 우리가 색인할 수 있고, 그런 색인된 정보를 추출해줄 수 있는 정보를 볼 수 있다.&lt;/li&gt;
&lt;li&gt;우리가 이 섹션에서는 이미지 검색을 예로 들지만, 이것을 통래 우리는 문자뿐만 아니라, 여러가지 부속적인 다른 방식의 데이터들도 색인이 가능하고, 이것을 통해 우리가 검색 기술을 확장할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image-20211206120458938.png&quot; data-origin-width=&quot;940&quot; data-origin-height=&quot;522&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GUX41/btrnevi46fp/gk5ZPe4lkiufBWHP7jZwm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GUX41/btrnevi46fp/gk5ZPe4lkiufBWHP7jZwm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GUX41/btrnevi46fp/gk5ZPe4lkiufBWHP7jZwm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGUX41%2Fbtrnevi46fp%2Fgk5ZPe4lkiufBWHP7jZwm1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;940&quot; height=&quot;522&quot; data-filename=&quot;image-20211206120458938.png&quot; data-origin-width=&quot;940&quot; data-origin-height=&quot;522&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;핀터레스트가 이런 질의 품질을 보여줄 수 있었던 과정은 빨강, 꽃 이러한 단어를 그자리에서 클래시피케이션한 것이 아니라, 오프라인으로 먼저 클래시피케이션하고, 이렇게 인지를 한 다음에 이것을 색인하여 이런 문서들에 추가를 함으로써 이렇게 RED FLOWER를 찾을때, 빨리빨리 , 그리고 매우 실시간으로 찾아줄 수 있는 결과를 가져오는 것이다.&lt;/li&gt;
&lt;li&gt;이미지 클래시피케이션과 지식그래프를 이용해 어마어마한 것을 할 수 있다. (비슷한 이미지 찾기, 같은 이미지 찾기 ,..)&lt;/li&gt;
&lt;li&gt;또한, 이러한 이미지 검색을 사용할 수 있는 요소들이 있다면, 꽃뿐만 아니라 사람의 얼굴까지도 판단할 수 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예를 들어, 반테러리즘을 위한 검색엔진을 만들겠다고 했을 때, 여러 사람들의 안면인식을 통해 비슷한 이미지가 어디서 나왔는지, 이사람 포스팅이 다른 소셜 네트워크의 어떤 사람과 연결되어있는지, 해서 이러한 네트워크를 구성하는데 도움이 될 수 있으며, 이 사람이 어느 cctv 에 포착이 되었을 떄, 이 포착된 사람이 다른 cctv 의 어느 이미지에 포착이 됐다. 이런 것을 통해 이 사람의 동선을 확인할 수 있고, 코로나 같은 재난 상황에서 동선을 확인하고, 격리대책을 만드는 데 도움을 줄 수 있는 이런 기술도 쉽게 만들 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;이미지 검색 활용도&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;유사 이미지 검색&lt;/li&gt;
&lt;li&gt;이미지, 동영상 저작권 검색&lt;/li&gt;
&lt;li&gt;유사한 제품 검색&lt;/li&gt;
&lt;li&gt;시장조사 ( 티비 시청률, sns 인지도 )&lt;/li&gt;
&lt;li&gt;메타 데이터 추론 및 추출&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;이미지 검색 사례&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;유사 이미지 검색&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;섹션으로 쪼개서 벡터화 : 픽셀로 잘라 해시를 적용&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;같은 이미지 찾기 가능,&lt;/li&gt;
&lt;li&gt;민들레를 섹션으로 쪼개 관찰해보면, 각 섹션에 민들레만 가질 수 있는 고유한 패턴(씨의 배열, 노랑-검정의 규칙적인 패턴)이 있을 수 있다.&lt;/li&gt;
&lt;li&gt;여기서 봤을때, 그러면 이런 섹션들을 쪼개서 RGB 로 나눠 우리가 만약에 추출을 하면, 추출해 =&amp;gt; 배열화하고=&amp;gt; 이 벡터를 해시화해서, 이 해시를 가진 이미지가 있다고 하는 경우, 왼쪽에 있는 민들레와 정확히 동일한 다른 이미지가 있다하면 이렇게 각 섹션마다 나누어서 해기를 만들어서 유사 일치를 하였을 떄는 일대일 매치가 나올 것입니다. 그래서 정확히 동일한 이미지가 나올 것입니다.&lt;/li&gt;
&lt;li&gt;만약에, 그 이미지가 조금이라도 잘렸다/ 크기가 스케일링 되었다, 하면, 이 섹션들이 만들어지는 데 문제가 생길 것입니다. 그래서 이 방법은 동일 이미지 자체에는 사용할 수 있겠지만, 유사이미지는 찾을 수 없을 듯 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image-20211206122239609.png&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;340&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cGyfnL/btrndmGUBjD/MVWLhpVibuKuf9ALEnqrKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cGyfnL/btrndmGUBjD/MVWLhpVibuKuf9ALEnqrKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cGyfnL/btrndmGUBjD/MVWLhpVibuKuf9ALEnqrKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcGyfnL%2FbtrndmGUBjD%2FMVWLhpVibuKuf9ALEnqrKk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;970&quot; height=&quot;340&quot; data-filename=&quot;image-20211206122239609.png&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;340&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;이미지에서 독특한 패턴 찾기: 이미지 자체에 있는 패턴 찾기&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;유사 이미지 찾기&lt;/li&gt;
&lt;li&gt;예를들어 이 배경과 하얀색이 만들어진 contour 을 우리가 표현해보았다. 이렇게 하면, 이런식의 패턴, 이런 움직임 굴곡들이 보일 수 있다.&lt;/li&gt;
&lt;li&gt;이런식으로 약간의 유사성을 확인할 수 있다.&lt;/li&gt;
&lt;li&gt;실제로 이 방식은 이미지 검색에서 매우 많이 사용되고 있다.&lt;/li&gt;
&lt;li&gt;우리는 이것을 square invariant feature transformation 이라 한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이미지가 작던지 크던지간에 상관없이 이렇게 같은 사이즈가 아니라해도 이 변화의 굴곡, 그리고 이 패턴만을 사용함으로써 그래서 이 변화가 어떻게 되는지 이것만을 기록함으로써 이미지가 작아지거나 커지더라도 확인할 수 있는 이런 방법들을 사용하는 알고리즘들이 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이런 형태로 유사 이미지검색이 가능해진다.&lt;/li&gt;
&lt;li&gt;한계: 같은 이미지들이 뭉쳐있는 경우, 아웃라인이 뭉개져 유사 이미지 검색이 안될 수 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;즉,여기서 cnn 등을 이용해 이미지 자체에 있는 인퍼런스를 추론하는 방식으로 할 것 입니다.&lt;/li&gt;
&lt;li&gt;하지만, 우리가 AI 로 들어가기 전에도 이러한 방식으로 여러가지 이미지 검색에 대한 결과를 찾아낼 수 있고, 추출할 수 있달 보여줬다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image-20211206153509152.png&quot; data-origin-width=&quot;942&quot; data-origin-height=&quot;359&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brT2qK/btrnc4NhrMA/UcgtfxIt6iHrMdYu1DCBCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brT2qK/btrnc4NhrMA/UcgtfxIt6iHrMdYu1DCBCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brT2qK/btrnc4NhrMA/UcgtfxIt6iHrMdYu1DCBCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrT2qK%2Fbtrnc4NhrMA%2FUcgtfxIt6iHrMdYu1DCBCk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;942&quot; height=&quot;359&quot; data-filename=&quot;image-20211206153509152.png&quot; data-origin-width=&quot;942&quot; data-origin-height=&quot;359&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;두 가지 융합도 가능하다.&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그래서 이렇게 우리가 Contour 를 만들어냈을 때, 이런 contour 사이에서 이제 이 비트 관련 해시를 만들 수 있다.&lt;/li&gt;
&lt;li&gt;그래서 각 부문마다 이렇게 해시를 나타내는 방식과 이렇게 contour 나타내는 방식 두개를 융합해보면, 우리가 만약에 이 contour 사이에 있는 부분만 이렇게 잘라서 여기서 비트를 이렇게 나눠볼 수 있을 것입니다.&lt;/li&gt;
&lt;li&gt;이 두개로 유사이미지 여부 판단은 매우 쉬워질 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;물론 이 검색 이미지에 추론을 더 추가하면 매우 정확도가 올라갈 것이다. 그래서 우리가 cnn 을 사용해 이런 추론의 정확도를 높이는 것 또한 같이 실습해보겠습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;동영상 저작권 검색&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 이미지 프레임마다 이미지 검색을 통해 이렇게 동영상의 저작권이나 아니면 동영상이 있는 여러 가지 추론을 만들어낼 수 있겠지만, 만약에 동영상이 있고, 이 비슷한 동영상이 존재하는데, 유사 여부 판단은 이미지 자체 데이터뿐만아니라, 민들레가 움직이는 방식, = 비트가 움직이는 방식을 통해 유사도 + 저작권 추론을 하고 있다.&lt;/li&gt;
&lt;li&gt;이 방식과 유사하게, 음악에도 적용되는데 소리가 움직이는 방식, 어떤 프리퀀시에서 몇 초 사이에서 스파이크가 있다 없다 똰, 우리가 이 변화 자체를 검색엔진에 색인할 수 있다. 그것을 통해 유사 음악이다 아니다를 처리할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image-20211206155305660.png&quot; data-origin-width=&quot;1025&quot; data-origin-height=&quot;390&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMQHuP/btrm3P4WHx2/IwQqJbHCkUR7ymQ6PwEb90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMQHuP/btrm3P4WHx2/IwQqJbHCkUR7ymQ6PwEb90/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMQHuP/btrm3P4WHx2/IwQqJbHCkUR7ymQ6PwEb90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMQHuP%2Fbtrm3P4WHx2%2FIwQqJbHCkUR7ymQ6PwEb90%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1025&quot; height=&quot;390&quot; data-filename=&quot;image-20211206155305660.png&quot; data-origin-width=&quot;1025&quot; data-origin-height=&quot;390&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이렇게 이미지, 영상, 음악, 가상현실 등이 색인이 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;이미지 색상 검색 실습1&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이번 실습은 아주 간단하게 이미지들을 처리해서 이미지에 있는 raw(red, green , blue) 색상만 검색하는 방식으로 실습을 진행해볼 예정입니다.&lt;/li&gt;
&lt;li&gt;이번에는 이미지들을 하나씩 처리함으로써 나오는 색상을 그냥 키워드에 추가하는 식으로 해서 진행을 해보겠습니다.&lt;/li&gt;
&lt;li&gt;이번 실습 목표 : 고급 이미지 처리가 아니라, 이미지 또한 로드함으로써 무엇인가 추가 데이터를 처리할 수 있다. 또하느 이러한 추론을 통해 여러 키워드 확장이 가능하다. 이것을 보여주는 취지이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;인덱스&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변화 없음. keywords 라는 이 메타데이터만 가지고, 작업을 진행함.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;ingestor&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;flower_classifier&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;# ingestor/flower_classifier/raw_color.py
from PIL import Image
import numpy as np

def get_dominant_rgb(image_file):
    # r, g, b  중에 어떤 색이 dominant 한지 알아보는 함수
    im = Image.open(image_file)
    pix = im.load()
    width = im.size[0]
    height = im.size[1]
    rgb_counters = { 'red': 0, 'green': 0, 'blue': 0}
    for y in range(0, height):
        for x in range(0, width):
            r,g,b = im.getpixel((x, y))
            rgb_counters[get_dominant_raw_color(r, g, b)] += 1
    highest_count = np.max(list(rgb_counters.values()))
    for k, v in rgb_counters.items():
        if v == highest_count:
            print(k)
            return k

def get_dominant_raw_color(r,g,b): # 255 30 199 =&amp;gt; red
    max_value = np.max([r,g,b])
    if r == max_value:
        return 'red'
    if g == max_value:
        return 'green'
    return 'blue&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;우세한 색상 키워드로 삽입&lt;/h4&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;import ast
import datetime
import hashlib
import json
import mysql.connector
import requests
import kg.kg_loader as kg_loader
import flower_classifier.tf_classifier as classifier
import flower_classifier.raw_color as raw_color

# SQL 에 연결하여 제품 페이지들을 추출하여 ProductPost array 로 돌려주는 함수입니다
def getPostings():
    wp_attachments_prefix = '../www/wp-content/uploads/' #  데이터베이스에 있는 이미지들이 이러한 파일 로케이션에 있기 떄문에  파일 이름을 쉽게 받아주기 위해 이런 prefix 를 넣었다.
    wp_attachments_url_prefix = 'http://localhost:8000/wp-content/uploads/' # 웹에서 찾을 떄, prefix
    kg_source = 'kg/kowiki-20210701-pages-articles-multistream-extracted.xml'
    wiki_kg = kg_loader.loadWikimedia(kg_source)
    cnx = mysql.connector.connect(user='root',
                                password='my_secret_pw',
                                host='localhost',
                                port=9906,
                                database='flowermall')
    cursor = cnx.cursor()
    # 2. Flower model 을 train 합니다.
    # class_names, model = classifier.build_flower_model()

    query = ('SELECT posts.ID AS id, posts.post_content AS content, posts.post_title AS title, posts.guid AS post_url, posts.post_date AS post_date, posts.post_modified AS modified_date, metadata.meta_value AS meta_value, image_data.meta_value AS image FROM wp_posts AS posts JOIN wp_postmeta AS image_metadata ON image_metadata.post_id = posts.ID JOIN wp_postmeta AS image_data ON image_data.post_id = image_metadata.meta_value JOIN wp_postmeta AS metadata ON metadata.post_id = posts.ID WHERE posts.post_status = &quot;publish&quot; AND posts.post_type = &quot;product&quot; AND metadata.meta_key = &quot;_product_attributes&quot; AND image_metadata.meta_key = &quot;_thumbnail_id&quot; AND image_data.meta_key = &quot;_wp_attached_file&quot;')
    cursor.execute(query)

    posting_list = []
    for (id, content, title, url, post_date, modified_date, meta_value, image) in cursor:
        print(&quot;Post {} found. URL: {}&quot;.format(id, url))
        meta_data = {}
        keywords = []
        image_url = wp_attachments_url_prefix + image
        image_file = wp_attachments_prefix + image # 이미지 파일의 위치 찾기
        # 1. Dominant raw color 를 추출합니다.
        dominant_color = raw_color.get_dominant_rgb(image_file)
        keywords.append(dominant_color)

        # 3. flower classification 을 통해 추가 데이터를 추출해 냅니다.
        # image_class, confidence = classifier.predict_class(title, image_url, class_names, model)
        #if (confidence &amp;gt; 0.8):
        #    print(image_url + ' is most likely ' + image_class)
        #    keywords.append(image_class)
        for n_gram in title.split():
            if n_gram in wiki_kg:
                print(&quot;found entry for &quot; + n_gram+dominant_color)
                meta_data = {**meta_data, **wiki_kg[n_gram]}
                subspecies = maybeGetSubspecies(wiki_kg[n_gram])
                if subspecies != None:
                    keywords.append(subspecies)
        product = ProductPost(id, content, title, url,
                              post_date, modified_date, assumeShippingLocation(meta_value), image, meta_data, &quot; &quot;.join(keywords))
        posting_list.append(product)

    cursor.close()
    cnx.close()
    return posting_list

&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;red 검색 결과&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image-20211206193139831.png&quot; data-origin-width=&quot;421&quot; data-origin-height=&quot;615&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbQEAK/btrndmUsXZq/hrYxP9mCjwwn4NGEBPf5V0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbQEAK/btrndmUsXZq/hrYxP9mCjwwn4NGEBPf5V0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbQEAK/btrndmUsXZq/hrYxP9mCjwwn4NGEBPf5V0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbQEAK%2FbtrndmUsXZq%2FhrYxP9mCjwwn4NGEBPf5V0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;421&quot; height=&quot;615&quot; data-filename=&quot;image-20211206193139831.png&quot; data-origin-width=&quot;421&quot; data-origin-height=&quot;615&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;red 장미 검색 결과&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image-20211206193233780.png&quot; data-origin-width=&quot;396&quot; data-origin-height=&quot;767&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cpfbex/btrm3PRrnkR/BoIH5j99A9DcKaor11kE4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cpfbex/btrm3PRrnkR/BoIH5j99A9DcKaor11kE4k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cpfbex/btrm3PRrnkR/BoIH5j99A9DcKaor11kE4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcpfbex%2Fbtrm3PRrnkR%2FBoIH5j99A9DcKaor11kE4k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;396&quot; height=&quot;767&quot; data-filename=&quot;image-20211206193233780.png&quot; data-origin-width=&quot;396&quot; data-origin-height=&quot;767&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;이미지 색상 검색 실습2 : 이미지 classification&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다음 실습으로는 우리가 이미지 처리의 꽃이라 할 수 있는 classification 을 이용해 이미지 처리에 정확도를 높이고, 우리가 검색엔진 기술과 어떻게 접목하는지 한 번 알아보자.&lt;/li&gt;
&lt;li&gt;cnn 을 이용해 이미지 레이블링 데이터를 사용해 정확도를 높일 것이다.&lt;/li&gt;
&lt;li&gt;tensorflow 가 꽃과 관련된 이미지 실습 데이터를 제공하기 떄문에 그것을 이용할 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;cmake&quot;&gt;&lt;code&gt;pip3 install -q tf-nigthly&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;import numpy as np
import os
import PIL
import tensorflow as tf
import ssl

from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras.models import Sequential

import pathlib

dataset_url = &quot;https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz&quot; # 3000
train_epoch_level = 10 # cnn 이 몇 가지 레벨이 있는지, 레벨 자체는 실무적으로 봤을때, 10 ~ 20 정도면 매우 적당하다. 
train_img_width = 180
train_img_height = 180

def build_flower_model():
    ssl._create_default_https_context = ssl._create_unverified_context
    data_dir = tf.keras.utils.get_file(
        'flower_photos', origin=dataset_url, untar=True)
    data_dir = pathlib.Path(data_dir)

    image_count = len(list(data_dir.glob('*/*.jpg')))
    print(&quot;training image count: &quot; + str(image_count))

    batch_size = 32

    train_ds = tf.keras.preprocessing.image_dataset_from_directory(
        data_dir,
        validation_split=0.2,
        subset=&quot;training&quot;,
        seed=123,
        image_size=(train_img_height, train_img_width),
        batch_size=batch_size)

    val_ds = tf.keras.preprocessing.image_dataset_from_directory(
        data_dir,
        validation_split=0.2,
        subset=&quot;validation&quot;,
        seed=123,
        image_size=(train_img_height, train_img_width),
        batch_size=batch_size)

    class_names = train_ds.class_names

    normalization_layer = layers.experimental.preprocessing.Rescaling(1./255)
    normalized_ds = train_ds.map(lambda x, y: (normalization_layer(x), y))
    image_batch, labels_batch = next(iter(normalized_ds))
    first_image = image_batch[0]
    # Notice the pixels values are now in `[0,1]`.
    print(np.min(first_image), np.max(first_image))

    num_classes = 5

    model = Sequential([
        layers.experimental.preprocessing.Rescaling(
            1./255, input_shape=(train_img_height, train_img_width, 3)),
        layers.Conv2D(16, 3, padding='same', activation='relu'),
        layers.MaxPooling2D(),
        layers.Conv2D(32, 3, padding='same', activation='relu'),
        layers.MaxPooling2D(),
        layers.Conv2D(64, 3, padding='same', activation='relu'),
        layers.MaxPooling2D(),
        layers.Flatten(),
        layers.Dense(128, activation='relu'),
        layers.Dense(num_classes)
    ])

    model.compile(optimizer='adam',
                loss=tf.keras.losses.SparseCategoricalCrossentropy(
                    from_logits=True),
                metrics=['accuracy'])

    history = model.fit(
        train_ds,
        validation_data=val_ds,
        epochs=train_epoch_level
    )

    return class_names, model

def predict_class(name, url, class_names, model):
    item_path = tf.keras.utils.get_file(name, origin=url)
    img = keras.preprocessing.image.load_img(
        item_path, target_size=(train_img_height, train_img_width)
    )
    img_array = keras.preprocessing.image.img_to_array(img)
    img_array = tf.expand_dims(img_array, 0)  # Create a batch

    predictions = model.predict(img_array)
    score = tf.nn.softmax(predictions[0])

    print(
        &quot;This image most likely belongs to {} with a {:.2f} percent confidence.&quot;
        .format(class_names[np.argmax(score)], 100 * np.max(score))
    )
    return class_names[np.argmax(score)], np.max(score)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;ingestor&lt;/h4&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;import ast
import datetime
import hashlib
import json
import mysql.connector
import requests
import kg.kg_loader as kg_loader
import flower_classifier.tf_classifier as classifier
import flower_classifier.raw_color as raw_color

# SQL 에 연결하여 제품 페이지들을 추출하여 ProductPost array 로 돌려주는 함수입니다
def getPostings():
    wp_attachments_prefix = '../www/wp-content/uploads/' #  데이터베이스에 있는 이미지들이 이러한 파일 로케이션에 있기 떄문에  파일 이름을 쉽게 받아주기 위해 이런 prefix 를 넣었다.
    wp_attachments_url_prefix = 'http://localhost:8000/wp-content/uploads/' # 웹에서 찾을 떄, prefix
    kg_source = 'kg/kowiki-20210701-pages-articles-multistream-extracted.xml'
    wiki_kg = kg_loader.loadWikimedia(kg_source)
    cnx = mysql.connector.connect(user='root',
                                password='my_secret_pw',
                                host='localhost',
                                port=9906,
                                database='flowermall')
    cursor = cnx.cursor()
    # 2. Flower model 을 train 합니다.
    class_names, model = classifier.build_flower_model()

    query = ('SELECT posts.ID AS id, posts.post_content AS content, posts.post_title AS title, posts.guid AS post_url, posts.post_date AS post_date, posts.post_modified AS modified_date, metadata.meta_value AS meta_value, image_data.meta_value AS image FROM wp_posts AS posts JOIN wp_postmeta AS image_metadata ON image_metadata.post_id = posts.ID JOIN wp_postmeta AS image_data ON image_data.post_id = image_metadata.meta_value JOIN wp_postmeta AS metadata ON metadata.post_id = posts.ID WHERE posts.post_status = &quot;publish&quot; AND posts.post_type = &quot;product&quot; AND metadata.meta_key = &quot;_product_attributes&quot; AND image_metadata.meta_key = &quot;_thumbnail_id&quot; AND image_data.meta_key = &quot;_wp_attached_file&quot;')
    cursor.execute(query)

    posting_list = []
    for (id, content, title, url, post_date, modified_date, meta_value, image) in cursor:
        print(&quot;Post {} found. URL: {}&quot;.format(id, url))
        meta_data = {}
        keywords = []
        image_url = wp_attachments_url_prefix + image
        image_file = wp_attachments_prefix + image # 이미지 파일의 위치 찾기
        # 1. Dominant raw color 를 추출합니다.
        dominant_color = raw_color.get_dominant_rgb(image_file)
        keywords.append(dominant_color)

        # 3. flower classification 을 통해 추가 데이터를 추출해 냅니다.
        image_class, confidence = classifier.predict_class(title, image_url, class_names, model)
        if (confidence &amp;gt; 0.8):
           print(image_url + ' is most likely ' + image_class)
           keywords.append(image_class)
        for n_gram in title.split():
            if n_gram in wiki_kg:
                print(&quot;found entry for &quot; + n_gram+dominant_color)
                meta_data = {**meta_data, **wiki_kg[n_gram]}
                subspecies = maybeGetSubspecies(wiki_kg[n_gram])
                if subspecies != None:
                    keywords.append(subspecies)
        product = ProductPost(id, content, title, url,
                              post_date, modified_date, assumeShippingLocation(meta_value), image, meta_data, &quot; &quot;.join(keywords))
        posting_list.append(product)

    cursor.close()
    cnx.close()
    return posting_list




p = getPostings()
postToElasticSearch(p)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;결과: pink rose -&amp;gt; rose 라는 단어를 사진에서 추출해 핑크 장비 부케에 키워드 추가했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image-20211206200201414.png&quot; data-origin-width=&quot;447&quot; data-origin-height=&quot;758&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KMed3/btrndHRCGmV/yArKMPLdeM7iKfb4DaRek0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KMed3/btrndHRCGmV/yArKMPLdeM7iKfb4DaRek0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KMed3/btrndHRCGmV/yArKMPLdeM7iKfb4DaRek0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKMed3%2FbtrndHRCGmV%2FyArKMPLdeM7iKfb4DaRek0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;447&quot; height=&quot;758&quot; data-filename=&quot;image-20211206200201414.png&quot; data-origin-width=&quot;447&quot; data-origin-height=&quot;758&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>SAS</category>
      <author>killog</author>
      <guid isPermaLink="true">https://etlwindy.tistory.com/24</guid>
      <comments>https://etlwindy.tistory.com/24#entry24comment</comments>
      <pubDate>Mon, 6 Dec 2021 20:04:25 +0900</pubDate>
    </item>
    <item>
      <title>패스트캠퍼스 엘라스틱서치  03. 지식 그래프(knowledge graph)를 활용해 검색 품질 향상하기</title>
      <link>https://etlwindy.tistory.com/23</link>
      <description>&lt;h1&gt;03. 지식 그래프(knowledge graph)를 활용해 검색 품질 향상하기&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위키피디아 같은 지식 그래프를 이용해 키워드를 확장시켜봅시다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;지식 그래프란&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SQL 과 달리, 지식을 그래프 형식으로 표현하여 새로운 정보의 추론과 여러가지 속성을 확장할 수 있는 새로운 종류의 그래프데이터베이스이다.&lt;/li&gt;
&lt;li&gt;여기서 보시다싶이 여러가지 &lt;b&gt;엔티티&lt;/b&gt;, 즉 아이디어 , 그리고 그 &lt;b&gt;컨셉들의 릴레이션쉽&lt;/b&gt;을 이렇게 그래프로 나타내주는 지식 그래프라는 컨셉이다.&lt;/li&gt;
&lt;li&gt;단순, SQL 로 이 관계들을 표현하려면 많은 테이블들, 그리고 무궁무진한 제한이 필요하겠지만, 이런 지식 그래프를 통해서 이런 엔티티를 하나하나 정리해주고, 이 엔티티 사이에 릴레이션을 정의해줌으로써, 매우 효과적인 데이터 스토어, 그리고 매우 impactful 한 inference 를 가져올 수 있습니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예) , 어느 대륙에 숭례문이 위치해 있는가?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;숭례문 -&amp;gt; 대한민국 -&amp;gt; 아시아 -&amp;gt; 대륙 !&lt;/li&gt;
&lt;li&gt;3 HOC 만에 답을 해결해줄 수 있다.&lt;/li&gt;
&lt;li&gt;검색에서 찾을 수 없는 이러한 inference 를 통해 존재하지 않는 정보들을 이런, transitivity , 그렇게 파도타기처럼 다른 로드로드 로 파도를 탐으로써 지식을 가져올 수 있는 이런 데이터가 나올 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image-20211204162105970.png&quot; data-origin-width=&quot;976&quot; data-origin-height=&quot;510&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/N4ndO/btrm9Fe7Fpy/vKGqpD9yAzye03GKWA3ko1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/N4ndO/btrm9Fe7Fpy/vKGqpD9yAzye03GKWA3ko1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/N4ndO/btrm9Fe7Fpy/vKGqpD9yAzye03GKWA3ko1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FN4ndO%2Fbtrm9Fe7Fpy%2FvKGqpD9yAzye03GKWA3ko1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;976&quot; height=&quot;510&quot; data-filename=&quot;image-20211204162105970.png&quot; data-origin-width=&quot;976&quot; data-origin-height=&quot;510&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image-20211204162905244.png&quot; data-origin-width=&quot;1061&quot; data-origin-height=&quot;503&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/poqLy/btrm5zT1RZM/1PL4KwKZ4jQ3G7eQlYUMt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/poqLy/btrm5zT1RZM/1PL4KwKZ4jQ3G7eQlYUMt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/poqLy/btrm5zT1RZM/1PL4KwKZ4jQ3G7eQlYUMt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpoqLy%2Fbtrm5zT1RZM%2F1PL4KwKZ4jQ3G7eQlYUMt1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1061&quot; height=&quot;503&quot; data-filename=&quot;image-20211204162905244.png&quot; data-origin-width=&quot;1061&quot; data-origin-height=&quot;503&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image-20211204163020701.png&quot; data-origin-width=&quot;1086&quot; data-origin-height=&quot;493&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8korX/btrmZ2oTZHb/ag4YGbvRuSj0bYY7X93fyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8korX/btrmZ2oTZHb/ag4YGbvRuSj0bYY7X93fyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8korX/btrmZ2oTZHb/ag4YGbvRuSj0bYY7X93fyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8korX%2FbtrmZ2oTZHb%2Fag4YGbvRuSj0bYY7X93fyK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1086&quot; height=&quot;493&quot; data-filename=&quot;image-20211204163020701.png&quot; data-origin-width=&quot;1086&quot; data-origin-height=&quot;493&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;플라워몰에 지식 그래프를 연계 예( 얼개만 )&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;튤립, 장미 , 민들레, 해바라기, 데이지&lt;/li&gt;
&lt;li&gt;백합과를 검색할 떄, 장미와 튤립이 나올 수 있도록&lt;/li&gt;
&lt;li&gt;어디 DB 에 저장할까?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;sql 에 저장해도되지만, 코스트가 있다.&lt;/li&gt;
&lt;li&gt;원초적으로 그리고, 자연적으로 더 빨리 , 엔티티 사이에 파도타기를 할 수 있게 전문화된 데이터베이스들이 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예. Neo4j, RedisGraph.. 여러 실전에 투여되고 있는 그래프 데이터베이스가 있다.&lt;/li&gt;
&lt;li&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;지식 그래프 활용사례&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;친구관계를 표현하기 위해 페이스북에서는 그래프 데이터베이스를 이용하고 있다.&lt;/li&gt;
&lt;li&gt;스마트 스피커: 아마존 알렉사
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;숭례문은 어느 대륙에 위치해? 같은 대답을 하기 위해서 지식 그래프를 이용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클로바는 현재 대답 못하네&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;SNS : 친구 관계, 포스팅 우선순위&lt;/li&gt;
&lt;li&gt;개인화된 교육 ㅣ 수학 컨셉을 설명하기 위한 관련 주제 연결 , 관련 토픽 복습 도움&lt;/li&gt;
&lt;li&gt;날씨 예측 : 날씨 는 수백 요소의 조합체이다.&lt;/li&gt;
&lt;li&gt;선거 공략&lt;/li&gt;
&lt;li&gt;교통 정책&lt;/li&gt;
&lt;li&gt;정부 오픈 데이터&lt;/li&gt;
&lt;li&gt;반테러/보안&lt;/li&gt;
&lt;li&gt;엔터테인먼트&lt;/li&gt;
&lt;li&gt;금융&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;지식그래프의 사례 : SNS&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;유저가 &quot;동남아 여행&quot;이라는 질의를 던졌을떄, 2촌 3촌간의 관계의 지인들의 &quot;동남아 여행&quot;에 관련된 컨텐츠를 RELEVANT 한 순위대로 보여줘 유저네게 어떤 컨텐츠의 의미를 부여할 수 있다.&lt;/li&gt;
&lt;li&gt;클러스터/클러스터링 = k means 또는 여러 클러스터링 알고리즘을 사용해 나타낼 수 있는 하나의 그룹핑을 만들어낸 것이다. 즉, 여러가지 커넥션들이 있지만, 이 커넥션들 사이에서 그 SUB GROUP 이 무엇인지, 그리고 이 SUB 그룹 사이에 어떠한 커넥션들이 있는지, 이러한 것들을 나타낼 수 있는 방법을 클러스터링이라고 한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이러한 클러스터링을 이용해 , 영희와 미자가 한 그루핑이고, 철수 재석 석이가 비슷한 클러스터링이다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그래서 만약, 동남아 여행에 관해 &quot;석&quot;이 포스팅을 올리는 경우,, 유저 간에 1대1로 연결되어있지 않지만, 이 유저와 절친인 철수, 그리고 재석과 깊은 연관을 가지고 있기 떄문에 이 스코어를 더 높게 줄 수 있습니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그래서 여기 우리 SR 소셜랭크라는 개념을 우리가 부여했다. 이러면, 랭크가 좀 더 높을 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;반면, 영희와 유저도 직접적으로 관련되어있는 반면, 스코어링이 낮아 유저와 미자는 큰 연관관계가 없다. (= 큰 소셜 랭크가 부여될 필요가 없다. )&lt;/li&gt;
&lt;li&gt;소셜랭크는 지금까지 소셜 네트워크를 사용하면서 여러가지 인터렉션들, 그리고 포스팅, 서로 코멘트를 달아주는 형식 등을 봄으로써 알아낼 수 있는 이런 시그널이 된다.&lt;/li&gt;
&lt;li&gt;따라서, 미자와 석이 동시에 동남아 포스팅을 올리면 석이 상단에 올라와야한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;마치 점수처럼 낮은 점수는 relevancy 가 낮고, 높은 점수는 relevancy 가 더 높다. 높은 점수는 상위, relevant 랭킹0한다.&lt;/li&gt;
&lt;li&gt;소셜랭킹 DB = 지식 그래프가 있는 경우, 랭킹에 지식 그래프가 이용될 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image-20211204164139810.png&quot; data-origin-width=&quot;1115&quot; data-origin-height=&quot;557&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JoPH6/btrmZl9293U/ZYBPmmTPMLvoVhxhyd15Yk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JoPH6/btrmZl9293U/ZYBPmmTPMLvoVhxhyd15Yk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JoPH6/btrmZl9293U/ZYBPmmTPMLvoVhxhyd15Yk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJoPH6%2FbtrmZl9293U%2FZYBPmmTPMLvoVhxhyd15Yk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1115&quot; height=&quot;557&quot; data-filename=&quot;image-20211204164139810.png&quot; data-origin-width=&quot;1115&quot; data-origin-height=&quot;557&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;지식 그래프 사례 : 개인화된 교육&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image-20211204214229008.png&quot; data-origin-width=&quot;1113&quot; data-origin-height=&quot;498&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1VlOk/btrmZH6Bj3G/VRdeIjqv6Nn2yd02k1jouK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1VlOk/btrmZH6Bj3G/VRdeIjqv6Nn2yd02k1jouK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1VlOk/btrmZH6Bj3G/VRdeIjqv6Nn2yd02k1jouK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1VlOk%2FbtrmZH6Bj3G%2FVRdeIjqv6Nn2yd02k1jouK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1113&quot; height=&quot;498&quot; data-filename=&quot;image-20211204214229008.png&quot; data-origin-width=&quot;1113&quot; data-origin-height=&quot;498&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;위키미디어 데이터를 사용해 지식 그래프 구현하기&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://dumps.wikimedia.org/kowiki/&quot;&gt;https://dumps.wikimedia.org/kowiki/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;위키미디아 데이터를 사용하여 관련 키워드 확장하기&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위키피디아에서 &quot;과&quot; 정보를 추출해 키워드에 추가해봅시다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;create_index2.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ingestor2.py&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;관련라이브러리
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;mwparserfromhell&lt;/code&gt; 이라는 라이브러리
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위키미디어의 데이터가 쉽게 parser 해주는 하나의 모듈이다.&lt;/li&gt;
&lt;li&gt;위키미디어 파일 형태의 파일인 어느 파일을 열게되면 이것을 이 라이브러리를 통해 parser 할 수 있게 해준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;# ingestor/kg/kg_loader.py
import mwparserfromhell
import re
import xml.etree.ElementTree as etree

def loadWikimedia(source_file):
    tree = etree.parse(source_file)
    root = tree.getroot()
    namespace = getNamspace(root.tag)
    kg = {}
    for page in root.findall('./' + namespace + 'page'):
        title = page.find(namespace + 'title').text
        page_content = page.findall(
            './' + namespace + 'revision/' + namespace + 'text')
        entry = {}
        if len(page_content) &amp;gt; 0:
            wikicode = mwparserfromhell.parse(page_content[0].text)
            templates = wikicode.filter_templates()
            for template in templates:
                #print(template.name)
                for param in template.params:
                    value = stripWikilinksForText(str(param.value)).strip()
                    if len(value) &amp;gt; 0:
                        entry[str(param.name).strip()] = value
        kg[title] = entry
    return kg

# 위키미디아 스타일 링크에서 텍스트만을 추출하는 helper function 입니다.
def stripWikilinksForText(wikilink):
    return re.sub(r'\[\[(.+?)\|.+?\]\]', r'\1', wikilink).replace('[[', '').replace(']]', '')

# XML 의 namespace 를 찾아 돌려줍니다.
def getNamspace(tag):
    return '{' + tag.split('}')[0].strip('{') + '}'
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;title 의 ngram 에서 wiki 에서 찾을시, data 를 추가해준다.&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 단어마다 위키미디아에 관련 정보를 찾아봅니다.title 을 공백별로 잘라서 위키미디어에서 관련 정보를 찾는다.&lt;br /&gt;예 : 흰색 장미 부케 -&amp;gt; 흰색 / 장미 / 부케&lt;/li&gt;
&lt;li&gt;gram: 우리가 이런 식으로 타이틀 또는 이런 쿼리를 나눌 떄, 각 단어를 보고 gram 이라 한다.&lt;br /&gt;하나의 그 subtext 그리고 text가 여러 개 있을 수 있기 떄문에 ngram 이라 부른다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;import ast
import datetime
import hashlib
import json
import mysql.connector
import requests
import kg.kg_loader as kg_loader

# SQL 에 연결하여 제품 페이지들을 추출하여 ProductPost array 로 돌려주는 함수입니다
def getPostings():
    kg_source = 'kg/kowiki-20210701-pages-articles-multistream-extracted.xml'
    wiki_kg = kg_loader.loadWikimedia(kg_source)
    cnx = mysql.connector.connect(user='root',
                                password='my_secret_pw',
                                host='localhost',
                                port=9906,
                                database='flowermall')
    cursor = cnx.cursor()

    query = ('SELECT posts.ID AS id, posts.post_content AS content, posts.post_title AS title, posts.guid AS post_url, posts.post_date AS post_date, posts.post_modified AS modified_date, metadata.meta_value AS meta_value, image_data.meta_value AS image FROM wp_posts AS posts JOIN wp_postmeta AS image_metadata ON image_metadata.post_id = posts.ID JOIN wp_postmeta AS image_data ON image_data.post_id = image_metadata.meta_value JOIN wp_postmeta AS metadata ON metadata.post_id = posts.ID WHERE posts.post_status = &quot;publish&quot; AND posts.post_type = &quot;product&quot; AND metadata.meta_key = &quot;_product_attributes&quot; AND image_metadata.meta_key = &quot;_thumbnail_id&quot; AND image_data.meta_key = &quot;_wp_attached_file&quot;')
    cursor.execute(query)

    posting_list = []
    for (id, content, title, url, post_date, modified_date, meta_value, image) in cursor:
        print(&quot;Post {} found. URL: {}&quot;.format(id, url))
        meta_data = {}
        keywords = []
        &quot;&quot;&quot;
        # 1. 각 단어마다 위키미디아에 관련 정보를 찾아봅니다.
        # title 을 공백별로 잘라서 위키미디어에서 관련 정보를 찾는다.
        예 : 흰색 장미 부케
        -&amp;gt; 흰색 / 장미 / 부케

        gram: 우리가 이런 식으로 타이틀 또는 이런 쿼리를 나눌 떄, 각 단어를 보고 gram 이라 한다.
        하나의 그 subtext 그리고 text가 여러 개 있을 수 있기 떄문에 ngram 이라 부른다.
        &quot;&quot;&quot;
        for n_gram in title.split():
           if n_gram in wiki_kg:
               print(&quot;found entry for &quot; + n_gram)
               meta_data = {**meta_data, **wiki_kg[n_gram]}
               subspecies = maybeGetSubspecies(wiki_kg[n_gram])
               if subspecies != None:
                   keywords.append(subspecies)
        product = ProductPost(id, content, title, url,
                              post_date, modified_date, assumeShippingLocation(meta_value), image, meta_data, &quot; &quot;.join(keywords))
        posting_list.append(product)

    cursor.close()
    cnx.close()
    return posting_list

# 2. 위키미디아 데이타에 특정한 attribute을 추출합니다.
# Subspecies field 가 해당 wiki data 에 존재하면 돌려줍니다. 아니면 None 을 돌려줍니다
def maybeGetSubspecies(wiki_page):
    sub_species_key = u'과'
    if sub_species_key in wiki_page:
        return wiki_page[sub_species_key]
    return None
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;taggerscript&quot;&gt;&lt;code&gt;(venv) kil@DESKTOP-LCIE51D:~/es_example/es/es_tutorial/es/ingestor$ python tools/check_es_index.py 
{&quot;took&quot;:3,&quot;timed_out&quot;:false,&quot;_shards&quot;:{&quot;total&quot;:1,&quot;successful&quot;:1,&quot;skipped&quot;:0,&quot;failed&quot;:0},&quot;hits&quot;:{&quot;total&quot;:{&quot;value&quot;:7,&quot;relation&quot;:&quot;eq&quot;},&quot;max_score&quot;:1.0,&quot;hits&quot;:[{&quot;_index&quot;:&quot;products&quot;,&quot;_type&quot;:&quot;_doc&quot;,&quot;_id&quot;:&quot;90063200dc4ce5dc4271f7bb1b9750e481a5c8f6&quot;,&quot;_score&quot;:1.0,&quot;_source&quot;:{
    &quot;content&quot;: &quot;\ub300\ud615 \ud654\ubd84\uc785\ub2c8\ub2e4. \uc0ac\uc774\uc988\ub294 13\&quot; \uc785\ub2c8\ub2e4.&quot;,
    &quot;id&quot;: 10,
    &quot;image_file&quot;: &quot;2021/07/terra-cotta-planter.jpg&quot;,
    &quot;keywords&quot;: &quot;&quot;,
    &quot;meta_data&quot;: {
        &quot;1&quot;: &quot;2&quot;,
        &quot;16\uc9c4\uc218\uac12&quot;: &quot;B66655&quot;,
        &quot;2&quot;: &quot;terracotta, terra cotta, terra-cotta&quot;,
        &quot;B&quot;: &quot;71&quot;,
        &quot;b&quot;: &quot;85&quot;,
        &quot;c&quot;: &quot;0&quot;,
        &quot;g&quot;: &quot;102&quot;,
        &quot;h&quot;: &quot;11&quot;,
        &quot;k&quot;: &quot;30&quot;,
        &quot;m&quot;: &quot;57&quot;,
        &quot;r&quot;: &quot;182&quot;,
        &quot;s&quot;: &quot;53&quot;,
        &quot;y&quot;: &quot;52&quot;,
        &quot;\uc81c\ubaa9&quot;: &quot;\ud14c\ub77c\ucf54\ud0c0&quot;
    },
    &quot;modified_date&quot;: &quot;2021-07-02T15:28:15&quot;,
    &quot;post_date&quot;: &quot;2021-07-01T18:55:54&quot;,
    &quot;shipped_from&quot;: &quot;\ud574\uc678&quot;,
    &quot;title&quot;: &quot;\ub300\ud615 \ud14c\ub77c\ucf54\ud0c0 \ud654\ubd84&quot;,
    &quot;url&quot;: &quot;http://localhost:8000/?post_type=product&amp;amp;#038;p=10&quot;
}},{&quot;_index&quot;:&quot;products&quot;,&quot;_type&quot;:&quot;_doc&quot;,&quot;_id&quot;:&quot;c483a0fd93699a19550df78d12a37245ba8b5079&quot;,&quot;_score&quot;:1.0,&quot;_source&quot;:{
    &quot;content&quot;: &quot;\ud558\uc580 \uaf43\ubcd1, 3\&quot; \ud55c\uac1c\uc640 \ud574\ubc14\ub77c\uae30 2\uc1a1\uc774\uac00 \ubc30\uc1a1\ub429\ub2c8\ub2e4.&quot;,
    &quot;id&quot;: 14,
    &quot;image_file&quot;: &quot;2021/07/sunflower.jpg&quot;,
    &quot;keywords&quot;: &quot;\uad6d\ud654\uacfc&quot;,
    &quot;meta_data&quot;: {
        &quot;1&quot;: &quot;\ud574\ubc14\ub77c\uae30 \uc528&quot;,
        &quot;2&quot;: &quot;Helianthus \ub610\ub294 sunflower&quot;,
        &quot;ISBN&quot;: &quot;9788993905755&quot;,
        &quot;\uacc4&quot;: &quot;\uc2dd\ubb3c&quot;,
        &quot;\uacfc&quot;: &quot;\uad6d\ud654\uacfc&quot;,
        &quot;\uadf8\ub9bc&quot;: &quot;Sunflower sky backdrop.jpg&quot;,
        &quot;\uae30\ud0c0&quot;: &quot;\uad6c\uacc4\uc6d0 \uc62e\uae40&quot;,
        &quot;\ub0a0\uc9dc&quot;: &quot;2011-11-01&quot;,
        &quot;\ubaa9&quot;: &quot;\uad6d\ud654\ubaa9&quot;,
        &quot;\ubbf8\ubd84\ub958_\uac15&quot;: &quot;\uc9c4\uc815\uc30d\ub5a1\uc78e\uc2dd\ubb3c&quot;,
        &quot;\ubbf8\ubd84\ub958_\ubaa9&quot;: &quot;\uad6d\ud654\uad70&quot;,
        &quot;\ubbf8\ubd84\ub958_\ubb38&quot;: &quot;\uc18d\uc528\uc2dd\ubb3c&quot;,
        &quot;\uc0c9&quot;: &quot;\uc2dd\ubb3c&quot;,
        &quot;\uc131&quot;: &quot;Nabhan&quot;,
        &quot;\uc18d&quot;: &quot;\ud574\ubc14\ub77c\uae30\uc18d&quot;,
        &quot;\uc544\uacfc&quot;: &quot;\uad6d\ud654\uc544\uacfc&quot;,
        &quot;\uc774\ub984&quot;: &quot;Gary Paul&quot;,
        &quot;\uc800\uc790&quot;: &quot;\uc560\ub108 \ud30c\ubcf4\ub974\ub4dc&quot;,
        &quot;\uc81c\ubaa9&quot;: &quot;2\ucc9c\ub144 \uc2dd\ubb3c \ud0d0\uad6c\uc758 \uc5ed\uc0ac : \uace0\ub300 \ud76c\uadc0 \ud544\uc0ac\ubcf8\uc5d0\uc11c \uadfc\ub300 \uc2dd\ubb3c\ub3c4\uac10\uae4c\uc9c0 \uc2dd\ubb3c \uc778\ubb38\ud559\uc758 \ubaa8\ub4e0 \uac83&quot;,
        &quot;\uc871&quot;: &quot;\ud574\ubc14\ub77c\uae30\uc871&quot;,
        &quot;\uc885&quot;: &quot;'''\ud574\ubc14\ub77c\uae30''' (''H. annuus'')&quot;,
        &quot;\ucd9c\ud310\uc0ac&quot;: &quot;\uae00\ud56d\uc544\ub9ac&quot;,
        &quot;\ud559\uba85&quot;: &quot;''Helianthus annuus''&quot;,
        &quot;\ud559\uba85_\uba85\uba85&quot;: &quot;\uce7c \ud3f0 \ub9b0\ub124, 1758&quot;
    },
    &quot;modified_date&quot;: &quot;2021-07-02T15:27:56&quot;,
    &quot;post_date&quot;: &quot;2021-07-01T19:01:43&quot;,
    &quot;shipped_from&quot;: &quot;\ud574\uc678&quot;,
    &quot;title&quot;: &quot;\uaf43\ubcd1\uc5d0 \ub2f4\uae34 \ud574\ubc14\ub77c\uae30 2\uc1a1\uc774&quot;,
    &quot;url&quot;: &quot;http://localhost:8000/?post_type=product&amp;amp;#038;p=14&quot;
}},&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;국화과&quot; 검색 결과&lt;/li&gt;
&lt;li&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;img.png&quot; data-origin-width=&quot;498&quot; data-origin-height=&quot;358&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cYS6Ee/btrm9E8nSUK/iuCNEF1V76zpluQcAoBtMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cYS6Ee/btrm9E8nSUK/iuCNEF1V76zpluQcAoBtMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cYS6Ee/btrm9E8nSUK/iuCNEF1V76zpluQcAoBtMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcYS6Ee%2Fbtrm9E8nSUK%2FiuCNEF1V76zpluQcAoBtMk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;498&quot; height=&quot;358&quot; data-filename=&quot;img.png&quot; data-origin-width=&quot;498&quot; data-origin-height=&quot;358&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이것은 지식그래프를 사용한 적절한 실전사례는 되지 않는다. 왜냐면 이렇게 키워드를 추가함으로써 우리가 effiecient 한 graph traverse 를 할 수 없기 떄문이다. 그렇기 떄문에 실전에서는 거의 대부분 인덱스 사이드에서 색인하는 과정에서 키워드를 추가하지 않고 , 우리가 쿼리, 즉, 해바라기 라는 쿼리가 들어왔을 때, 해바라기의 과가 국화과라는 것을 우리가 알기때문에 , 국화과라는 키워드를 그냥 추가해서 찾아볼 수 있게 도와준다.&lt;/li&gt;
&lt;li&gt;아니면 국화과라는 키워드가 왔을 때, 국화과인 해바라기, 그리고 민들레 이런 것을 키워드에 추가해서 색인을 찾아보는 방식으로 실전에서는 진행한다.&lt;/li&gt;
&lt;li&gt;하지만, 우리 예제에서는 인덱싱 사이드에서 어떻게 위키피디아 페이지를 사용해 이 속성을 확정할 수 있는지 알아 보았습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image-20211205174158324.png&quot; data-origin-width=&quot;498&quot; data-origin-height=&quot;358&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xtFRS/btrmZJcgCKo/TNnnzhGLt3TmvymWZ6i0rk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xtFRS/btrmZJcgCKo/TNnnzhGLt3TmvymWZ6i0rk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xtFRS/btrmZJcgCKo/TNnnzhGLt3TmvymWZ6i0rk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxtFRS%2FbtrmZJcgCKo%2FTNnnzhGLt3TmvymWZ6i0rk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;498&quot; height=&quot;358&quot; data-filename=&quot;image-20211205174158324.png&quot; data-origin-width=&quot;498&quot; data-origin-height=&quot;358&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 위키피디아나 이런 그래프를 이용해 색인 과정에서 이렇게 확장성을 늘릴 수 있고, 키워드에 관련 검색어를 이렇게 늘릴 수 있습니다. 또한, 실전에서는 이것이 물론 색인뿐만 아니라, 쿼리 과정에서 쿼리를 확장하는데 사용이 됩니다. 그래서 내가 '국화과&quot;라는 단어를 검색했을 떄, 국화과에 관련된 해바라기, 또는 민들레를 쿼리에 추가해 , 국화과 또는 장미 이렇게 쿼리를 확장하는대로 사용할 수 있다.&lt;/p&gt;</description>
      <category>SAS</category>
      <author>killog</author>
      <guid isPermaLink="true">https://etlwindy.tistory.com/23</guid>
      <comments>https://etlwindy.tistory.com/23#entry23comment</comments>
      <pubDate>Mon, 6 Dec 2021 11:52:59 +0900</pubDate>
    </item>
    <item>
      <title>ngram</title>
      <link>https://etlwindy.tistory.com/22</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;N-gram은 문자열에서 N개의 연속된 요소를 추출하는 방법입니다. 만약&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;'Hello'&lt;/span&gt;라는 문자열을 문자(글자) 단위 2-gram으로 추출하면 다음과 같이 됩니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;He
el
ll
lo
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 문자열의 처음부터 문자열 끝까지 한 글자씩 이동하면서 2글자를 추출합니다. 3-gram은 3글자, 4-gram은 4글자를 추출하겠죠?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출처 : &lt;a href=&quot;https://dojang.io/mod/page/view.php?id=2332&quot;&gt;https://dojang.io/mod/page/view.php?id=2332&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출처: &lt;a href=&quot;https://wikidocs.net/21692&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://wikidocs.net/21692&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;2-n-gram&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. N-gram&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 임의의 개수를 정하기 위한 기준을 위해 사용하는 것이 n-gram입니다. n-gram은 n개의 연속적인 단어 나열을 의미합니다. 갖고 있는 코퍼스에서 n개의 단어 뭉치 단위로 끊어서 이를 하나의 토큰으로 간주합니다. 예를 들어서 문장 An adorable little boy is spreading smiles이 있을 때, 각 n에 대해서 n-gram을 전부 구해보면 다음과 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1638677741210&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;unigrams : an, adorable, little, boy, is, spreading, smiles
bigrams : an adorable, adorable little, little boy, boy is, is spreading, spreading smiles
trigrams : an adorable little, adorable little boy, little boy is, boy is spreading, is spreading smiles
4-grams : an adorable little boy, adorable little boy is, little boy is spreading, boy is spreading smiles&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;n-gram을 사용할 때는 n이 1일 때는 유니그램(unigram), 2일 때는 바이그램(bigram), 3일 때는 트라이그램(trigram)이라고 명명하고 n이 4 이상일 때는 gram 앞에 그대로 숫자를 붙여서 명명합니다. 출처에 따라서는 유니그램, 바이그램, 트라이그램 또한 각각 1-gram, 2-gram, 3-gram이라고 하기도 합니다. 이제 n-gram을 이용한 언어 모델을 설계해보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;n-gram을 통한 언어 모델에서는 다음에 나올 단어의 예측은 오직 n-1개의 단어에만 의존합니다. 예를 들어&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;'An adorable little boy is spreading'&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;다음에 나올 단어를 예측하고 싶다고 할 때, n=4라고 한 4-gram을 이용한 언어 모델을 사용한다고 합시다. 이 경우, spreading 다음에 올 단어를 예측하는 것은 n-1에 해당되는 앞의 3개의 단어만을 고려합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;627&quot; data-origin-height=&quot;144&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/L2UAr/btrm0pxhrwW/Pj7BA4zgR0PTf0g8Ti6xbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/L2UAr/btrm0pxhrwW/Pj7BA4zgR0PTf0g8Ti6xbk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/L2UAr/btrm0pxhrwW/Pj7BA4zgR0PTf0g8Ti6xbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FL2UAr%2Fbtrm0pxhrwW%2FPj7BA4zgR0PTf0g8Ti6xbk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;627&quot; height=&quot;144&quot; data-origin-width=&quot;627&quot; data-origin-height=&quot;144&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;P(w|boy is spreading)=count(boy is spreading&amp;nbsp;w)count(boy is spreading)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 갖고있는 코퍼스에서 boy is spreading가 1,000번 등장했다고 합시다. 그리고 boy is spreading insults가 500번 등장했으며, boy is spreading smiles가 200번 등장했다고 합시다. 그렇게 되면 boy is spreading 다음에 insults가 등장할 확률은 50%이며, smiles가 등장할 확률은 20%입니다. 확률적 선택에 따라 우리는 insults가 더 맞다고 판단하게 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;287&quot; data-origin-height=&quot;77&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdR0Gn/btrm3Melh7J/XPRXLPPReD6xaKChgv9fGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdR0Gn/btrm3Melh7J/XPRXLPPReD6xaKChgv9fGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdR0Gn/btrm3Melh7J/XPRXLPPReD6xaKChgv9fGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdR0Gn%2Fbtrm3Melh7J%2FXPRXLPPReD6xaKChgv9fGk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;287&quot; height=&quot;77&quot; data-origin-width=&quot;287&quot; data-origin-height=&quot;77&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;h2 id=&quot;3-n-gram-language-model&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. N-gram Language Model의 한계&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 4-gram을 통한 언어 모델의 동작 방식을 확인했습니다. 그런데 조금 의문이 남습니다. 앞서 본 4-gram 언어 모델은 주어진 문장에서 앞에 있던 단어인&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;'작고 사랑스러운(an adorable little)'&lt;/b&gt;이라는 수식어를 제거하고, 반영하지 않았습니다. 그런데&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;'작고 사랑스러운'&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;수식어까지 모두 고려하여&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;작고 사랑하는 소년&lt;/b&gt;이 하는 행동에 대해 다음 단어를 예측하는 언어 모델이었다면 과연 '작고 사랑스러운 소년이'&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;'모욕을 퍼트렸다'&lt;/b&gt;라는 부정적인 내용이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;'웃음 지었다'&lt;/b&gt;라는 긍정적인 내용 대신 선택되었을까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 코퍼스 데이터를 어떻게 가정하느냐의 나름이고, 전혀 말이 안 되는 문장은 아니지만 여기서 지적하고 싶은 것은 n-gram은 뒤의 단어 몇 개만 보다 보니 의도하고 싶은 대로 문장을 끝맺음하지 못하는 경우가 생긴다는 점입니다. 문장을 읽다 보면 앞 부분과 뒷부분의 문맥이 전혀 연결 안 되는 경우도 생길 수 있습니다. 결론만 말하자면, 전체 문장을 고려한 언어 모델보다는 정확도가 떨어질 수밖에 없습니다. 이를 토대로 n-gram 모델에 대한 한계점을 정리해보겠습니다.&lt;/p&gt;
&lt;h3 id=&quot;1-sparsity-problem&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(1) 희소 문제(Sparsity Problem)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문장에 존재하는 앞에 나온 단어를 모두 보는 것보다 일부 단어만을 보는 것으로 현실적으로 코퍼스에서 카운트 할 수 있는 확률을 높일 수는 있었지만, n-gram 언어 모델도 여전히 n-gram에 대한 희소 문제가 존재합니다.&lt;/p&gt;
&lt;h3 id=&quot;2-n-trade-off&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(2) n을 선택하는 것은 trade-off 문제.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에서 몇 개의 단어를 볼지 n을 정하는 것은 trade-off가 존재합니다. 임의의 개수인 n을 1보다는 2로 선택하는 것은 거의 대부분의 경우에서 언어 모델의 성능을 높일 수 있습니다. 가령, spreading만 보는 것보다는 is spreading을 보고 다음 단어를 예측하는 것이 더 정확하기 때문입니다. 이 경우 훈련 데이터가 적절한 데이터였다면 언어 모델이 적어도 spreading 다음에 동사를 고르지 않을 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;n을 크게 선택하면 실제 훈련 코퍼스에서 해당 n-gram을 카운트할 수 있는 확률은 적어지므로 희소 문제는 점점 심각해집니다. 또한 n이 커질수록 모델 사이즈가 커진다는 문제점도 있습니다. 기본적으로 코퍼스의 모든 n-gram에 대해서 카운트를 해야 하기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;n을 작게 선택하면 훈련 코퍼스에서 카운트는 잘 되겠지만 근사의 정확도는 현실의 확률분포와 멀어집니다. 그렇기 때문에 적절한 n을 선택해야 합니다. 앞서 언급한 trade-off 문제로 인해 정확도를 높이려면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;n은 최대 5를 넘게 잡아서는 안 된다고 권장&lt;/b&gt;되고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;n이 성능에 영향을 주는 것을 확인할 수 있는 유명한 예제 하나를 보겠습니다. 스탠퍼드 대학교의 공유 자료에 따르면, 월스트리트 저널에서 3,800만 개의 단어 토큰에 대하여 n-gram 언어 모델을 학습하고, 1,500만 개의 테스트 데이터에 대해서 테스트를 했을 때 다음과 같은 성능이 나왔다고 합니다. 뒤에서 배우겠지만, 펄플렉서티(perplexity)는 수치가 낮을수록 더 좋은 성능을 나타냅니다.&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;398&quot; data-origin-height=&quot;73&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8CTc9/btrmYTZQmqG/zhgyolD9vS5aeE7AHIrqQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8CTc9/btrmYTZQmqG/zhgyolD9vS5aeE7AHIrqQK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8CTc9/btrmYTZQmqG/zhgyolD9vS5aeE7AHIrqQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8CTc9%2FbtrmYTZQmqG%2FzhgyolD9vS5aeE7AHIrqQK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;398&quot; height=&quot;73&quot; data-origin-width=&quot;398&quot; data-origin-height=&quot;73&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;br /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 결과는 n을 1에서 2, 2에서 3으로 올릴 때마다 성능이 올라가는 것을 보여줍니다.&lt;/p&gt;
&lt;h2 id=&quot;4-domain&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. 적용 분야(Domain)에 맞는 코퍼스의 수집&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 분야인지, 어떤 어플리케이션인지에 따라서 특정 단어들의 확률 분포는 당연히 다릅니다. 가령, 마케팅 분야에서는 마케팅 단어가 빈번하게 등장할 것이고, 의료 분야에서는 의료 관련 단어가 당연히 빈번하게 등장합니다. 이 경우 언어 모델에 사용하는 코퍼스를 해당 도메인의 코퍼스를 사용한다면 당연히 언어 모델이 제대로 된 언어 생성을 할 가능성이 높아집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;때로는 이를 언어 모델의 약점이라고 하는 경우도 있는데, 훈련에 사용된 도메인 코퍼스가 무엇이냐에 따라서 성능이 비약적으로 달라지기 때문입니다.&lt;/p&gt;
&lt;h2 id=&quot;5-neural-network-based-language-model&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5. 인공 신경망을 이용한 언어 모델(Neural Network Based Language Model)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서는 다루지 않겠지만, N-gram Language Model의 한계점을 극복하기위해 분모, 분자에 숫자를 더해서 카운트했을 때 0이 되는 것을 방지하는 등의 여러 일반화(generalization) 방법들이 존재합니다. 하지만 그럼에도 본질적으로 n-gram 언어 모델에 대한 취약점을 완전히 해결하지는 못하였고, 이를 위한 대안으로 N-gram Language Model보다 대체적으로 성능이 우수한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;인공 신경망을 이용한 언어 모델&lt;/b&gt;이 많이 사용되고 있습니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;인공 신경망을 이용한 언어 모델&lt;/b&gt;은 8챕터에서 배웁니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이해를 돕는 추천 자료 : &lt;a href=&quot;https://www.edwith.org/deepnlp/lecture/29214/&quot;&gt;https://www.edwith.org/deepnlp/lecture/29214/&lt;/a&gt;&lt;br /&gt;조경현 교수님이 n-gram 언어 모델에 대해서 강의하시는 파트입니다.&lt;br /&gt;스탠포드 대학교 강의 자료 : &lt;a href=&quot;https://web.stanford.edu/~jurafsky/slp3/3.pdf&quot;&gt;https://web.stanford.edu/~jurafsky/slp3/3.pdf&lt;/a&gt;&lt;br /&gt;뉴욕대학교 강의 자료 : &lt;a href=&quot;https://cs.nyu.edu/courses/spring17/CSCI-UA.0480-009/lecture3-and-half-n-grams.pdf&quot;&gt;https://cs.nyu.edu/courses/spring17/CSCI-UA.0480-009/lecture3-and-half-n-grams.pdf&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>용어정리</category>
      <author>killog</author>
      <guid isPermaLink="true">https://etlwindy.tistory.com/22</guid>
      <comments>https://etlwindy.tistory.com/22#entry22comment</comments>
      <pubDate>Sun, 5 Dec 2021 13:19:43 +0900</pubDate>
    </item>
    <item>
      <title>패스트캠퍼스 엘라스틱 서치 Part1. 검색엔진 기술의 개요</title>
      <link>https://etlwindy.tistory.com/21</link>
      <description>&lt;h1&gt;Part1. 검색엔진 기술의 개요&lt;/h1&gt;
&lt;h2&gt;01-01. 강의 개요&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;검색 엔진 기술의 개요&lt;/li&gt;
&lt;li&gt;엘라스틱 서치를 사용해 간단한 쇼핑몰 검색 기능 만들기(실습 위주)&lt;/li&gt;
&lt;li&gt;지식 그래프의 개요(실습 포함)&lt;/li&gt;
&lt;li&gt;이미지 처리를 활용해 검색 결과를 향상시키기(실습위주)&lt;/li&gt;
&lt;li&gt;검색랭킹(실습 포함) : 방대한 빅 데이터에서 검색 결과를 돌려줄 때, 어떠한 결과가 더 연관성(relevance)한지, 더 먼저 나와야하는지 , 사용자의 주의를 끄는 것(attention)이 더 필요한 것인지 이것을 찾아 주는 것이 검색 랭킹이다. 또한, relevance 라고 부르기도 한다.&lt;/li&gt;
&lt;li&gt;검색 기술에 대한 기본 지식&lt;/li&gt;
&lt;li&gt;검색엔진 중급 클래스인 엘라스틱서치를 활용해 고급 검색 엔진 만들기 강의&lt;/li&gt;
&lt;li&gt;이 강의를 통해 검색 엔진 기술이 무엇인지, 그리고 검색엔진들은 어떤 아키텍처로 디자인 되어 있는지&lt;/li&gt;
&lt;li&gt;다른 기술과 어떠한 장점과 단점을 가지고 있는지&lt;/li&gt;
&lt;li&gt;엘라스틱서치를 활용해 고급 검색엔진 기능들을 추가하는 실습&lt;/li&gt;
&lt;li&gt;검색엔진 기술들을 배우고, 검색 엔진이 어떤 동기에서 시작되었는지,&lt;/li&gt;
&lt;li&gt;그리고, 검색 엔진의 기본 아키텍처 MySQL 이나 NoSQL 과 비교해 검색엔진이 어떤 차이가 있는지&lt;/li&gt;
&lt;li&gt;실리콘밸리에서 검색엔진 기술 등을 활용해 어떤 기능들을 구현하고 있는지 배워볼 예정&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;what we will learn&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;검색 기술에 대한 기본 지식&lt;/li&gt;
&lt;li&gt;엘라스틱서치를 활용한 검색 시스템 구축&lt;/li&gt;
&lt;li&gt;지식 그래프, 부속처리 기술들을 사용한 고급 검색 기술 활용법&lt;/li&gt;
&lt;li&gt;검색 랭킹의 기본 지식, 검색 결과의 개인화에 대한 개요&lt;/li&gt;
&lt;li&gt;예제를 통한 위 기술들에 대한 기본적인 실습&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;what should i take this course&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;빅데이터의 경쟁력은 데이터를 최대한 빠르고 효율적으로 정리해주는 기술이다.&lt;/li&gt;
&lt;li&gt;현존하는 데이터 규모는 현재도 폭발적인 성장을 하고 있다.&lt;/li&gt;
&lt;li&gt;빅데이터를 다룰 줄 아는 자가 빅데이터의 패러다임을 이끄는 기업의 핵심 전문가가 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;01-03. 검색엔진 기술의 개요&lt;/h2&gt;
&lt;h3&gt;개요&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;검색엔진 기술이란?&lt;/li&gt;
&lt;li&gt;SQL, NoSQL 비교&lt;/li&gt;
&lt;li&gt;검색엔진 기술의 기본 아키텍처&lt;/li&gt;
&lt;li&gt;실리콘밸리에 검색 기술활용사례&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;검색엔진 시스템이란&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;컴퓨터 시스템에 저장된 정보를 찾아주는 것을 도와주도록 설계된 정보 검색 시스템(출처ㅣ 위키피디아)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;검색 시스템들의 사례&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;오프라인&lt;ul&gt;
&lt;li&gt;파일검색, 데스크탑 검색(마이크로소프트 코타나)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;검색 서비스&lt;ul&gt;
&lt;li&gt;웹 검색, 이미지 검색, 비디오, 오디오 검색 등등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;인터페이스형&lt;ul&gt;
&lt;li&gt;인공지능 개인비서 : 아마존 알렉사, 삼성 빅스비 등&lt;/li&gt;
&lt;li&gt;지도형 : 카카오맵, 배달앱등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;추론형&lt;ul&gt;
&lt;li&gt;부동산 : zillow , redfin&lt;/li&gt;
&lt;li&gt;여러 데이터들을 종합하여 추론을 inference as a service 방식으로 제공해주는 서비스도 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;01-04. SQL 과 검색 엔진 비교&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;요약 : scale, speed, and usefulness&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;SQL&lt;/th&gt;
&lt;th&gt;검색엔진&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;* transaction 을 위해 제작된 데이터 베이스 * acid라는 property를 제공해주는 큰 장점을 가지고 있습니다. * acid : atomic, consistent, isolated, and durable 의 줄임말이다. * acid 는 모든 트랜잭션이 commit 이 되면 이뤄졌다는 것이 확실해지고, 모든것이 확실해졌다는 말의 줄임말&lt;/td&gt;
&lt;td&gt;*검색엔진은 ACID 속성을 제공해주지 않고 있다.검색엔진은 결과가 stale 해질 수 있고, 없는 결과가 나타날 수 있고, 데이터가 바뀌어도 반영되는데 시간이 걸릴 수 있습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ACIDic, even in read replica&lt;/td&gt;
&lt;td&gt;Queries returned in near constant time ~O(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Slow down as data size increases O(log N)&lt;/td&gt;
&lt;td&gt;Data can expand almost infinitely&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Realtime up-to-date data&lt;/td&gt;
&lt;td&gt;data can be stale&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Advanced search features/ rankinf very difficult&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;linear increase in traffic can cause exponential decay in service speed&lt;/td&gt;
&lt;td&gt;Traffic increase is unrelated to the system itself, serving systems can grow linearly with the traffic&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;sql 데이터베이스들은 구체적으로 b-tree 나 linear scan 들을 사용해 결국엔 데이터사이즈가 커지면 커질 수록 속도가 줄어드는 이런 단점을 가지고 있다.&lt;/li&gt;
&lt;li&gt;반대로 검색 엔진은 데이터 사이즈가 커지더라도 전혀 상관없이 결과를 거의 커스텀 타임에 돌려줄 수 있는 매우 강력한 장점을 가지고 있다.&lt;/li&gt;
&lt;li&gt;시간복잡도가 sql 엔진은 O(n) 또는 O(log N) 을 가지는 현상이 있는데, 검색엔진은 o(1)을 가진 혁기적인 데이터베이스라 볼 수 있다.&lt;/li&gt;
&lt;li&gt;sql 은 realtime 데이터를 제공할 수 있는 장점을 가지고 있다. sql 에 저장된 데이터는 realtime 으로 바로 반영이 되고 바로 모든 subscribe 들이 볼 수 있는 이러한 데이터인 반면에&lt;/li&gt;
&lt;li&gt;검색엔진은 데이터가 추가되고 인덱싱되고, 그리고 서빙되는데 꽤 큰 시간이 필요하다.&lt;/li&gt;
&lt;li&gt;sql 로 제공된 검색 결과들은 고급 검색결과, 랭킹 등을 도입하기 매우 힘들다. sql 자체가 transactional nature 를 위해 만들어진 데이터베이스이기 때문에 이 위에 고급 텍스트 manipulation , 오디오 이미지 프로세싱 이런 것들을 추가하기에 매우 벅차다.&lt;/li&gt;
&lt;li&gt;반면 검색엔진은, 무제한 advanced search feature를 추가할 수 있는 장점이 있다.&lt;/li&gt;
&lt;li&gt;sql 는 serving traffic 이 늘어나면 늘어날 수록 serving speed가 기하급수적으로 감소할 수 있다. 즉, 사용자가 Linearly 증가할 수록 service는 exponentially 더 비싼 코스트를 요구하게 된다.&lt;/li&gt;
&lt;li&gt;반면에 검색 엔진은 트래픽이 늘어나도, 부하 속도는 일정적으로 유지된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;01-05. 검색엔진 색인 개요&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;검색엔진 기술 핵심을 한 마디로 축출한다면, 인덱싱 = 색인을 꼽을 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;01-06. 검색엔진 아키텍처&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image-20211128171809117.png&quot; data-origin-width=&quot;2322&quot; data-origin-height=&quot;1058&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkOoXv/btrmKCKt4K1/ECUwb1xfbOOQDNwCexWhP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkOoXv/btrmKCKt4K1/ECUwb1xfbOOQDNwCexWhP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkOoXv/btrmKCKt4K1/ECUwb1xfbOOQDNwCexWhP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkOoXv%2FbtrmKCKt4K1%2FECUwb1xfbOOQDNwCexWhP1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2322&quot; height=&quot;1058&quot; data-filename=&quot;image-20211128171809117.png&quot; data-origin-width=&quot;2322&quot; data-origin-height=&quot;1058&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;빅데이터&lt;/li&gt;
&lt;li&gt;수집, 주석 시스템&lt;ul&gt;
&lt;li&gt;인터넷 동영상 사이트 그리고 음악 사이트 같은데서 들어오는 raw 데이터를 추가해주고 거기에 추가 메타데이터 추가해주는 역할&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;주석 데이터 저장소&lt;/li&gt;
&lt;li&gt;색인 시스템&lt;ul&gt;
&lt;li&gt;데이터 읽고 색인 생성하는 과정&lt;/li&gt;
&lt;li&gt;여러 단어들과 그리고 annotation 을 찾아 색인을 만든다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;색인들&lt;ul&gt;
&lt;li&gt;인덱싱 또는 색인시스템들이 추출해낸 결과는 일종의 색인 또는 색인들로 만들어져 저장된다.&lt;/li&gt;
&lt;li&gt;이렇게 해서 생성된 색인들은 서빙 시스템들이 사용하기 편하게 분리돼 저장할 수 있다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;컬렉션 분석 시스템들&lt;ul&gt;
&lt;li&gt;색인들을 이용해 쿼리 또는 사용자의 질문들을 서빙하게 된다.&lt;/li&gt;
&lt;li&gt;그리하여 사용자가 자연어로 질문 또는 쿼리를 요청하면 오른쪽에 보이는 쿼리 엔진, 또는 쿼리 처리 시스템들이 이러한 자연어를 서빙시스템이 이해하기 편하게 다시 재분석해주고 이러한 쿼리들을 소팅 또는 랭킹 시스템이 여러가지 컬렉션 애널리시스템에 보내게 됩니다. 그리하여 이런 컬렉션 애널리시스, 또는 분석 시스템들은 이렇게 분산된 색인들 사이에서 필요한 정보들을 추출해 소팅 , 또는 랭킹 시스템에 돌려주게 되고, 소팅 랭킹 시스템은 여기서 돌아온 결과들을 종합하고 머지하여 제일 유용하고, 제일 효과적인 결과를 돌려주게됩니다. 이 돌려진 결과물들은 쿼리 처리 시스템이 다시 한번 사용자에게 보기 편한 방식으로 리턴하게 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;정렬 시스템&lt;/li&gt;
&lt;li&gt;쿼리 처리 시스템&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;01-07. NoSQL 과 검색엔진&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image-20211128174238403.png&quot; data-origin-width=&quot;1216&quot; data-origin-height=&quot;500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4Qmc2/btrmGV4VGdq/LGdPIXilS9IPZpOcqwRq0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4Qmc2/btrmGV4VGdq/LGdPIXilS9IPZpOcqwRq0k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4Qmc2/btrmGV4VGdq/LGdPIXilS9IPZpOcqwRq0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4Qmc2%2FbtrmGV4VGdq%2FLGdPIXilS9IPZpOcqwRq0k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1216&quot; height=&quot;500&quot; data-filename=&quot;image-20211128174238403.png&quot; data-origin-width=&quot;1216&quot; data-origin-height=&quot;500&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;그러면 하나의 쿼리가 정확히 서빙 시스템에 어떻게 전달되고 이 결과가 다시 돌아오는지 자세히 봅시다.&lt;/li&gt;
&lt;li&gt;색인들은 아까 언급된 topological sorting 과 같은 방식으로 정렬이 되어있기 때문에 소팅 랭킹 시스템을 정확히 어떤 컬렉션 분석 시스템에 이쿼리를 보내야 할지 미리 알고 있을 수 있습니다. =&amp;gt; 전체적인 시스템 부하를 줄일 수 있다.&lt;/li&gt;
&lt;li&gt;그래서 fox 와 brown 이라는 단어를 가지고 있는 컬렉션 분석 시스템들은 이 단어들을 가지고 있는 문서들을&lt;br&gt;다시 소팅 랭킹 시스템에 보내줄 수 있고, 이렇게 보내진 결과는 소팅, 랭킹 시스템이 하나로 뭉쳐서 다시 쿼리 처리 시스템에 보낼 수 있게 됩니다.&lt;/li&gt;
&lt;li&gt;이렇게 돌아온 결과들은 소팅 랭킹 시스템들이 통합한 결과로 뭉쳐 merge 하여 뭐리 엔진 처리 시스템에 돌려주게 됩니다.&lt;/li&gt;
&lt;li&gt;이렇게 돌려진 결과는 사용자가 보기 편하게 다시 돌려지겠죠.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;자 그러면 여기서 여러가지 질문들을 할 수 있겠죠. 예를들어 brown fox 가 브랜드 이름인지, 브랜드 이름이라면, brown 과 fox 라는 단어가 따로 떨어져 있으면 안되겠죠. 그래서 brown 이라는 단어와 fox 라는 단어가 한 문장에 가까우면 가까울 수록 더 중요한 문서가 될 수 있고, 또한, 그러한 경우라면, fox가 brown 보다 먼저오는 문장은 별로 중요해지지 않겠죠.&lt;/p&gt;
&lt;p&gt;그래서 이런 문자들을 토대로 정렬해주는 것을 랭킹 섹션에서 배우게 될 것입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;NoSQL DB들과 어떤 것이 다른가요?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;자 그러면 검색엔진 시스템들이 NoSQL 데이터베이스들과 어떻게 다른가요?&lt;ul&gt;
&lt;li&gt;NosqL 은 sql 과 달리 acid property를 제공하지 않고 보통은 더 좋은 consistnecy 아니면 더 좋은 partition tolerance 아니면 더 좋은 availability 를 제공해주는 새로운 종류의 데이터 서비스들&lt;/li&gt;
&lt;li&gt;cap 이론&lt;ul&gt;
&lt;li&gt;현존하는 거의 모든 , 모든 데이터를 저장하는 매체들은 이 세가지 중 두 가지만을 추구할 수 있다는 이론이다.&lt;/li&gt;
&lt;li&gt;예를들어 sql 은 consistency를 추구하는 데이터베이스이다. 반면에, 검색엔진 같은 서비스들은 availability 그리고 partition tolerance 를 축으로 하는 서비스이다. = consistency 를 버렸다. 즉, 검색엔진 색인에서는 만약에 하나의 문서가 변경됐을때, 색인이 변경되는데 시간이 걸리고, 그 사이에 consistency 가 추구되지 않을 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bC6V0x/btrmJiTjCU7/B4HT2KOuAK2C8DefPEaFNK/img.png&quot; alt=&quot;img&quot;&gt;&lt;/p&gt;
&lt;h2&gt;01-08 검색엔진의 실리콘밸리 사례&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Quora&lt;ul&gt;
&lt;li&gt;자연어, 관련 검색&lt;/li&gt;
&lt;li&gt;여러 사람이 자신의 질문을 올리고, 그것을 답해주는 지식인 서비스&lt;/li&gt;
&lt;li&gt;내가 검색하는 질의에 자신의 질문 뿐만 아니라, 질문에 있는 중요한 단어들을 축출하여 의미있는 질문의 답들을 볼 수 있는 이러한 인터페이스를 제공하고 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;pinterest&lt;ul&gt;
&lt;li&gt;이미지 검색 서비스&lt;/li&gt;
&lt;li&gt;글자 뿐만 아니라, 이미지에 있는 여러 요소들을 사용하여 이미지 검색을 도와주고 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;soundhound&lt;ul&gt;
&lt;li&gt;음원 검색&lt;/li&gt;
&lt;li&gt;사용자가 스마트폰으로 자기가 듣고 있는 음악을 녹음하면 이 음악이 무엇인지 찾아주는 서비스 제공&lt;/li&gt;
&lt;li&gt;음악 소리들도 주석화처리를 통해 검색 기술이 손쉽게 찾아주는 놀라운 효과를 볼 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Palantir&lt;ul&gt;
&lt;li&gt;data insight&lt;/li&gt;
&lt;li&gt;여러가지 데이터들을 종합하여 사용자들이 보고 추론 내리기 편한 인터페이스들을 제공하고 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;23andme&lt;ul&gt;
&lt;li&gt;dna 검색&lt;/li&gt;
&lt;li&gt;여러가지 데이터들을 종합하여 사용자들이 보고 추론을 dna 에 적용&lt;/li&gt;
&lt;li&gt;Dna 분석 결과를 토대로 나와 dna 가 가장 일치하는 사람을 찾아주어 실종된 미아, 그리고 잊고 있던 자신의 혈통을 찾아주는 서비스&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h1&gt;Part2. ElasticSearch 로 간단한 쇼핑몰 검색 기능 만들기&lt;/h1&gt;
&lt;h2&gt;02-01. 엘라스틱 서치 개요&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;엘라스틱 서치는 인덱싱, 컬렉션 애널리시스, 그리고 소팅과 랭킹 섹션에 포함되는 기능을 처리하는 시스템이라 볼 수 있습니다.&lt;ul&gt;
&lt;li&gt;엘라스틱서치와더불어 ingestion annotaion 을 도와주는 로그스태시(logstash), 쿼리처리를 도와주는 키바나(kibana)가 함께 사용되는 경우가 많다.&lt;/li&gt;
&lt;li&gt;이 세 가지 제품을 통합하여 ELK 라는 Stack 으로 사용되고 있다.&lt;ul&gt;
&lt;li&gt;로그스태시 : ingestion 과 annotation을 필요한 여러가지 메타 데이터 추출, 그리고 injestion 파이프라인에 들어가는 많은 데이터 소스들의 커넥션을 도와주는 기능들을 가지고 있습니다.&lt;/li&gt;
&lt;li&gt;키바나 (Kibana) 는 쿼리 처리에 도움이 되는 인터페이스를 그리고 인터페이스를 확장할 수 잇는 이런 도구들을 추구하고 있습니다.&lt;/li&gt;
&lt;li&gt;엘라스틱은 이 녹색섹션에서 보시다 싶이 색인, 그리고 색인을 생성하고, collection analysis, 소팅 랭킹 그리고 기본적인 쿼리를 도와주는 기능을 첨부하고 있습니다.&lt;/li&gt;
&lt;li&gt;또한, 구체적으로 엘라스틱 서치는 apache foundation 이 제공하고 있는 LUCENE 라는 인덱싱 서비스를 사용하고 있습니다.&lt;ul&gt;
&lt;li&gt;이 인덱싱 서비스 위에서 색인 생성 시스템이 인덱싱 서비스 위에 색인 생성 시스템, 그리고 소팅 , 랭킹, 애널리시스 서비스를 덧붙인 것이 엘라스틱 서치라 볼 수 있습니다.&lt;br&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image-20211128183608097.png&quot; data-origin-width=&quot;2578&quot; data-origin-height=&quot;1366&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbRO1D/btrmK8oEQhJ/COuyu91W6E1KQJGeDbhA0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbRO1D/btrmK8oEQhJ/COuyu91W6E1KQJGeDbhA0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbRO1D/btrmK8oEQhJ/COuyu91W6E1KQJGeDbhA0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbRO1D%2FbtrmK8oEQhJ%2FCOuyu91W6E1KQJGeDbhA0K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2578&quot; height=&quot;1366&quot; data-filename=&quot;image-20211128183608097.png&quot; data-origin-width=&quot;2578&quot; data-origin-height=&quot;1366&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;02-02. 플라워몰에 검색 기능 추가하기&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;엘라스틱서치에 대한 컨셉이 들어가게 되는데, 엘라스틱서치는 인덱스 또는 색인 하나만 서빙하는 것이 아니라 여러 가지 색인을 따로 만들어 제공할 수 있게 디자인되어있다. 그렇기 때문에 각 색인을 만들떄마다 인덱스를 만드는 과정이 필요하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;인덱스에 대한 설명&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;색인 만드는 api&lt;ul&gt;
&lt;li&gt;RESR 를 어떤 방식으로 만들 수 있는지 나온다.&lt;ul&gt;
&lt;li&gt;put, post 를 이용해 새로운 인덱스를 만들 수 있다.&lt;ul&gt;
&lt;li&gt;index는 TARGET 이라는 이름으로 만들 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html&quot;&gt;https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;색인 생성&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;엘라스틱 서치는 여러 인덱싱을 제공해주기 때문에 인덱싱을 하나하나 만들어야한다. 인덱스의 이름에 맞춰 문서가 따로 정렬된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;# ingestor/create_index1.py
import requests
import json

url = &amp;quot;http://localhost:9200/products&amp;quot; # 엘라스틱 서치 주소

payload = json.dumps({
    &amp;quot;settings&amp;quot;: {
        &amp;quot;index&amp;quot;: {
            &amp;quot;number_of_shards&amp;quot;: 1, # 인덱스, 색인을 나누는 분산 숫자, 1인 경우 분산하지 않고 모든 인덱스를 하나에 저장하기 위해 만듬.
          # number_of_shards 가 100 ,number_of_replicas 가 10 인 경우 = 색인이 100개로 나눠진다.
          # 모든 100개의 샤드가 레플레카를 10개씩 가지게 된다. = 총 1000개의 서빙 인덱스가 생기는 것
          # = 스케일링을 위해 필요한 요소이다.
            &amp;quot;number_of_replicas&amp;quot;: 1
            # replica 는 AVAILABILITY 를 위해 존재하는 것이다.
            # SHARD 는 역시 PERFORMANCE 를 위해 존재하는 것이다.
            # 더 빨리 병행하도록 로드밸런싱을 하기 위해 존재하는 것이다.

        },
        &amp;quot;analysis&amp;quot;: {
            &amp;quot;analyzer&amp;quot;: {
                &amp;quot;analyzer-name&amp;quot;: {
                    &amp;quot;type&amp;quot;: &amp;quot;custom&amp;quot;,
                    &amp;quot;tokenizer&amp;quot;: &amp;quot;keyword&amp;quot;, # 토큰 키워드 방식
                    &amp;quot;filter&amp;quot;: &amp;quot;lowercase&amp;quot; # 들어오는 키워드들을 lowercase
                }
            }
        }
    },
    &amp;quot;mappings&amp;quot;: {
        &amp;quot;properties&amp;quot;: {
            &amp;quot;id&amp;quot;: {
                &amp;quot;type&amp;quot;: &amp;quot;long&amp;quot;
            },
            &amp;quot;content&amp;quot;: {
                &amp;quot;type&amp;quot;: &amp;quot;text&amp;quot;
            },
            &amp;quot;title&amp;quot;: {
                &amp;quot;type&amp;quot;: &amp;quot;text&amp;quot;
            },
            &amp;quot;url&amp;quot;: {
                &amp;quot;type&amp;quot;: &amp;quot;text&amp;quot;
            },
            &amp;quot;image_file&amp;quot;: {
                &amp;quot;type&amp;quot;: &amp;quot;text&amp;quot;
            },
            &amp;quot;post_date&amp;quot;: {
                &amp;quot;type&amp;quot;: &amp;quot;date&amp;quot;
            },
            &amp;quot;modified_date&amp;quot;: {
                &amp;quot;type&amp;quot;: &amp;quot;date&amp;quot;
            },
            &amp;quot;shipped_from&amp;quot;: {
                &amp;quot;type&amp;quot;: &amp;quot;text&amp;quot;
            }
        }
    }
})
headers = {
    &amp;#39;Content-Type&amp;#39;: &amp;#39;application/json&amp;#39;
}

response = requests.request(&amp;quot;PUT&amp;quot;, url, headers=headers, data=payload)

print(response.text)&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;ES 인덱스 스키마 확인&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# ingestor/tools/get_es_schema.py
import requests

url = &amp;quot;http://localhost:9200/products&amp;quot;

payload = &amp;quot;&amp;quot;
headers = {}

response = requests.request(&amp;quot;GET&amp;quot;, url, headers=headers, data=payload)

print(response.text)&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;ES 인덱스 스키마 지우기&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# ingestor/tools/delete_index.py
import requests

url = &amp;quot;http://localhost:9200/products&amp;quot;

payload = &amp;quot;&amp;quot;
headers = {}

response = requests.request(&amp;quot;DELETE&amp;quot;, url, headers=headers, data=payload)
# PRODUCTS 라는 인덱스 지우기
print(response.text)&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;인덱스에 데이터 추가하기&lt;/h3&gt;
&lt;p&gt;자 이제 우리가 생성한 이 products라는 인덱스의 쇼핑데이터들을 injest 하는 injestor 라는 코드를 돌려보겠습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# ingestor/ingestor1.py
p = getPostings()
postToElasticSearch(p)&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;ingestor1.py 에서 getPostings 라는 function 이 있습니다.&lt;ul&gt;
&lt;li&gt;SQL 에 연결하여 제품 페이지들을 추출하여 ProductPost array 로 돌려주는 함수입니다&lt;/li&gt;
&lt;li&gt;ingestion 을 대신하는 함수&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;# ingestor/ingestor1.py
# SQL 에 연결하여 제품 페이지들을 추출하여 ProductPost array 로 돌려주는 함수입니다
def getPostings():
    cnx = mysql.connector.connect(user=&amp;#39;root&amp;#39;,
                                password=&amp;#39;my_secret_pw&amp;#39;,
                                host=&amp;#39;localhost&amp;#39;,
                                port=9906,
                                database=&amp;#39;flowermall&amp;#39;)
    cursor = cnx.cursor()

    query = (&amp;#39;SELECT posts.ID AS id, posts.post_content AS content, posts.post_title AS title, posts.guid AS post_url, posts.post_date AS post_date, posts.post_modified AS modified_date, metadata.meta_value AS meta_value, image_data.meta_value AS image FROM wp_posts AS posts JOIN wp_postmeta AS image_metadata ON image_metadata.post_id = posts.ID JOIN wp_postmeta AS image_data ON image_data.post_id = image_metadata.meta_value JOIN wp_postmeta AS metadata ON metadata.post_id = posts.ID WHERE posts.post_status = &amp;quot;publish&amp;quot; AND posts.post_type = &amp;quot;product&amp;quot; AND metadata.meta_key = &amp;quot;_product_attributes&amp;quot; AND image_metadata.meta_key = &amp;quot;_thumbnail_id&amp;quot; AND image_data.meta_key = &amp;quot;_wp_attached_file&amp;quot;&amp;#39;)
    cursor.execute(query)

    posting_list = []
    for (id, content, title, url, post_date, modified_date, meta_value, image) in cursor:
        print(&amp;quot;Post {} found. URL: {}&amp;quot;.format(id, url))
        product = ProductPost(id, content, title, url,
                             post_date, modified_date, assumeShippingLocation(meta_value), image)
        posting_list.append(product)

    cursor.close()
    cnx.close()
    return posting_list&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;# 아주 naive 한 출고지 extraction subroutine
# 간단한 처리를 해서 넣어줌을 강조
def assumeShippingLocation(raw_php_array):
    if u&amp;#39;국내&amp;#39; in raw_php_array:
        return &amp;#39;국내&amp;#39;
    return &amp;#39;해외&amp;#39;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;이 POSTING 들을 엘라스틱서치에 색인을 보내는 함수가 필요하다&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;help function&lt;/h4&gt;
&lt;h5&gt;엘라스틱서치에서 사용될 문서의 고유 아이디를 생성&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;# ingestor/ingestor1.py
# 우리가 고유 문서에대한 특정 id 를 찾아서 이 ID 를 통해 중복이되는 것을 막기 위해 이렇게 생성하고 있다. :`getUniqueIndexId`
# 엘라스틱서치에서 사용될 문서의 고유 아이디를 생성합니다.
def getUniqueIndexId(url):
    return hashlib.sha1(url.encode(&amp;#39;utf-8&amp;#39;)).hexdigest()&lt;/code&gt;&lt;/pre&gt;&lt;h5&gt;색인 도큐먼트&lt;/h5&gt;
&lt;p&gt;&lt;a href=&quot;https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html&quot;&gt;https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;문서를 색인화할 수 있는 이런 API들이 제공되고 있다.&lt;ul&gt;
&lt;li&gt;target : 인덱스 이름 제공&lt;/li&gt;
&lt;li&gt;_doc : 내가 문서를 색인하고 싶다.&lt;/li&gt;
&lt;li&gt;post : 엘라스틱서치가 이 문서에 대한 고유 id를 직접 만들 수 있고, POST 를 사용하지 않는 경우, put 을 사용해 직접 사용자가 id 를 제공할 수 있게 되어있다.&lt;ul&gt;
&lt;li&gt;우리 예제의 경우, 우리가 직접 ID 를 생성한다.&lt;/li&gt;
&lt;li&gt;그 이유는 우리가 고유 문서에대한 특정 id 를 찾아서 이 ID 를 통해 중복이되는 것을 막기 위해 이렇게 생성하고 있다. :&lt;code&gt;getUniqueIndexId&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;sha1이라는 hash를 통해 그냥 string 을 만들고 있다. sha1은 고유 id를 고유 text 에서 만들어지는 이러한 hash function 입니다.&lt;ul&gt;
&lt;li&gt;이 hash는 똑같은 문자가 왔을때, 똑같은 코드를 제공해주는 deterministic function 들로 같은 문서가 같은 ID 를 만들 수 있게 제공해주는 이런 FUNCTION 들입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;PUT /&amp;lt;target&amp;gt;/_doc/&amp;lt;_id&amp;gt;
POST /&amp;lt;target&amp;gt;/_doc/
PUT /&amp;lt;target&amp;gt;/_create/&amp;lt;_id&amp;gt;
POST /&amp;lt;target&amp;gt;/_create/&amp;lt;_id&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h5&gt;formatting function&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;json_field_handler&lt;ul&gt;
&lt;li&gt;만약 json 에 datetime field 가 있으면, 알아듣기 쉬운 isoformat 으로 만들어주는 help function&lt;/li&gt;
&lt;li&gt;json 을 cover datetime 같은 이런 field 들을 json을 convert할때, 에러가 생기지 않게 도와주는 function 이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;pre&gt;&lt;code&gt;# ingestor/ingestor1.py
# Custom handlers for marshalling python object into JSON 
def json_field_handler(x):
    if isinstance(x, datetime.datetime):
        return x.isoformat()
    raise TypeError(&amp;amp;amp;quot;Unable to parse json field&amp;amp;amp;quot;)&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;# ingestor/ingestor1.py
# 엘라스틱서치에 출력하는 함수입니다.
def postToElasticSearch(products):
    putUrlPrefix = &amp;#39;http://localhost:9200/products/_doc/&amp;#39;
    headers = {&amp;#39;Content-type&amp;#39;: &amp;#39;application/json&amp;#39;, &amp;#39;Accept&amp;#39;: &amp;#39;text/plain&amp;#39;}
    for product in products:
        id = getUniqueIndexId(product.url)
        print(id)
        r = requests.put(putUrlPrefix + id, data=json.dumps(product.__dict__, # put 실패하면, 형식과 필드가 일치하는지 다시 확인
                        indent=4, sort_keys=True, default=json_field_handler), headers=headers)
        if r.status_code &amp;gt;= 400: # 에러핸들링용
           print(&amp;quot;There is an error writing to elasticsearch&amp;quot;)
           print(r.status_code)
           print(r.json())&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;isoformat&lt;/code&gt; 은 이 파이썬이 제공하는 이런, datetime format 과 다르기 떄문에 이렇게 변경이 필요합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;잘 들어왔는지, check_es_index.py 로 확인&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;# ingestor/tools/check_es_index.py
import requests

url = &amp;quot;http://localhost:9200/products/_search&amp;quot;

payload = {}
headers = {}

response = requests.request(&amp;quot;GET&amp;quot;, url, headers=headers, data=payload)

print(response.text)&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;결과&lt;ul&gt;
&lt;li&gt;&lt;pre&gt;&lt;code&gt;$ python tools/check_es_index.py 
{
    &amp;quot;took&amp;quot;:868, #   걸린 시간 ms 단위이다. ,sql 보다 훨씬 빠른시간, 데이터 수가 많아져도 큰 변화가 생기지 않는다.
     &amp;quot;timed_out&amp;quot;:false,  # 타임 아웃이 발생했는가
     &amp;quot;_shards&amp;quot;:{&amp;quot;total&amp;quot;:1,&amp;quot;successful&amp;quot;:1,&amp;quot;skipped&amp;quot;:0,&amp;quot;failed&amp;quot;:0},# shard= 색인을 몇 개로 나누었는지
    &amp;quot;hits&amp;quot;:
        {
            &amp;quot;total&amp;quot;:{&amp;quot;value&amp;quot;:7,&amp;quot;relation&amp;quot;:&amp;quot;eq&amp;quot;}, # hit 이 7개가 되어 돌아옴
            &amp;quot;max_score&amp;quot;:1.0,# 제일 높은 문서의 score 가 있다. 추 후에 설명 예정
            &amp;quot;hits&amp;quot;:
                [
                    {
                        &amp;quot;_index&amp;quot;:&amp;quot;products&amp;quot;,
                        &amp;quot;_type&amp;quot;:&amp;quot;_doc&amp;quot;,
                        &amp;quot;_id&amp;quot;:&amp;quot;90063200dc4ce5dc4271f7bb1b9750e481a5c8f6&amp;quot;, # 생성된 _id 확인, sha 로 생성된 hex code
                          &amp;quot;_score&amp;quot;:1.0, 
                        &amp;quot;_source&amp;quot;:{
                                        &amp;quot;content&amp;quot;: &amp;quot;\ub300\ud615 \ud654\ubd84\uc785\ub2c8\ub2e4. \uc0ac\uc774\uc988\ub294 13\&amp;quot; \uc785\ub2c8\ub2e4.&amp;quot;,
                                        &amp;quot;id&amp;quot;: 10, 
                                        &amp;quot;image_file&amp;quot;: &amp;quot;2021/07/terra-cotta-planter.jpg&amp;quot;,
                                        &amp;quot;modified_date&amp;quot;: &amp;quot;2021-07-02T15:28:15&amp;quot;,
                                        &amp;quot;post_date&amp;quot;: &amp;quot;2021-07-01T18:55:54&amp;quot;,
                                        &amp;quot;shipped_from&amp;quot;: &amp;quot;\ud574\uc678&amp;quot;,
                                        &amp;quot;title&amp;quot;: &amp;quot;\ub300\ud615 \ud14c\ub77c\ucf54\ud0c0 \ud654\ubd84&amp;quot;,
                                        &amp;quot;url&amp;quot;: &amp;quot;http://localhost:8000/?post_type=product&amp;amp;#038;p=10&amp;quot;
}},..]}}&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;직접 elastic search 에 질의 던져보기&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;elastic search 에 질의를 직접 검색해볼 수 있게 도와주는 &lt;code&gt;_search&lt;/code&gt; 라는 API 가 있다.&lt;/li&gt;
&lt;li&gt;원하고 싶은 index 에 _search 를 한 다음 쿼리를 주면, 이쿼리에 대한 결과가 돌아온다.&lt;/li&gt;
&lt;li&gt;이런 형태로 &amp;quot;장미&amp;quot;라고 던졌을때, 두가지 포스팅이 돌아오는 것을 볼 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://127.0.0.1:9200/products/_search?q=%EC%9E%A5%EB%AF%B8&quot;&gt;http://127.0.0.1:9200/products/_search?q=장미&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;pre&gt;&lt;code&gt;{
    &amp;quot;took&amp;quot;:6, #   걸린 시간 ms 단위이다. ,sql 보다 훨씬 빠른시간, 데이터 수가 많아져도 큰 변화가 생기지 않는다.
    &amp;quot;timed_out&amp;quot;:false, # 타임 아웃이 발생했는가
    &amp;quot;_shards&amp;quot;:{&amp;quot;total&amp;quot;:1,&amp;quot;successful&amp;quot;:1,&amp;quot;skipped&amp;quot;:0,&amp;quot;failed&amp;quot;:0},,# shard= 색인을 몇 개로 나누었는지
    &amp;quot;hits&amp;quot;: {
    &amp;quot;total&amp;quot;:{&amp;quot;value&amp;quot;:2,&amp;quot;relation&amp;quot;:&amp;quot;eq&amp;quot;},# hit 이 2개가 되어 돌아옴
    &amp;quot;max_score&amp;quot;:1.2060539,# 제일 높은 문서의 score 가 있다. 추 후에 설명 예정
    &amp;quot;hits&amp;quot;:    [{
    &amp;quot;_index&amp;quot;:&amp;quot;products&amp;quot;,
    &amp;quot;_type&amp;quot;:&amp;quot;_doc&amp;quot;,
    &amp;quot;_id&amp;quot;:&amp;quot;a8f6acf14f68c56b2d4edfab139d393a7058f877&amp;quot;,
    &amp;quot;_score&amp;quot;:1.2060539,
    &amp;quot;_source&amp;quot;:{
        &amp;quot;content&amp;quot;: &amp;quot;\ud06c\uace0\uc791\uc740 \ud551\ud06c\uc0c9 \uc7a5\ubbf8\ub4e4\ub85c \ubd80\ucf00\ub97c \ub9cc\ub4e4\uc5b4 \ubcf4\uc558\uc2b5\ub2c8\ub2e4.&amp;quot;,
        &amp;quot;id&amp;quot;: 18,
           &amp;quot;image_file&amp;quot;: &amp;quot;2021/07/pink_rose_bouquet.jpg&amp;quot;,
        &amp;quot;modified_date&amp;quot;: &amp;quot;2021-07-02T15:27:42&amp;quot;,
        &amp;quot;post_date&amp;quot;: &amp;quot;2021-07-01T19:05:02&amp;quot;,
        &amp;quot;shipped_from&amp;quot;: &amp;quot;\ud574\uc678&amp;quot;,
        &amp;quot;title&amp;quot;: &amp;quot;\ud551\ud06c\ube5b \uc7a5\ubbf8 \ubd80\ucf00&amp;quot;,
        &amp;quot;url&amp;quot;: &amp;quot;http://localhost:8000/?post_type=product&amp;amp;#038;p=18&amp;quot;
}},...
]}}&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;플라워몰 웹사이트에 엘라스틱 검색 연결하기&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;1) 쇼핑몰 : http://127.0.0.1:8000/
2) 검색 페이지 추가 : www/search.php&lt;/code&gt;&lt;/pre&gt;</description>
      <category>SAS</category>
      <author>killog</author>
      <guid isPermaLink="true">https://etlwindy.tistory.com/21</guid>
      <comments>https://etlwindy.tistory.com/21#entry21comment</comments>
      <pubDate>Wed, 1 Dec 2021 23:21:51 +0900</pubDate>
    </item>
    <item>
      <title>wal</title>
      <link>https://etlwindy.tistory.com/20</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124;&quot;&gt;로그 선행 기입(write-ahead logging,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;WAL&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124;&quot;&gt;)은 데이터베이스 시스템에서 ACID의 특성 가운데 원자성과 내구성을 제공하는 기술의 한 계열이다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;WAL&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124;&quot;&gt;을 사용하는 시스템에서 모든 수정은 적용 이전에 로그에 기록된다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>용어정리</category>
      <author>killog</author>
      <guid isPermaLink="true">https://etlwindy.tistory.com/20</guid>
      <comments>https://etlwindy.tistory.com/20#entry20comment</comments>
      <pubDate>Mon, 22 Nov 2021 13:19:21 +0900</pubDate>
    </item>
    <item>
      <title>혁신적인 언어 중, 영어 구분법</title>
      <link>https://etlwindy.tistory.com/17</link>
      <description>&lt;p&gt;F.lower(F.col(&amp;quot;column&amp;quot;))==F.upper(F.col(&amp;quot;column&amp;quot;)) 같은지 확인&lt;/p&gt;</description>
      <category>spark</category>
      <author>killog</author>
      <guid isPermaLink="true">https://etlwindy.tistory.com/17</guid>
      <comments>https://etlwindy.tistory.com/17#entry17comment</comments>
      <pubDate>Fri, 29 Oct 2021 10:45:17 +0900</pubDate>
    </item>
    <item>
      <title>WSGI(Web Server Gateway Interface=웹 서버 게이트웨이 인터페이스)</title>
      <link>https://etlwindy.tistory.com/16</link>
      <description>&lt;h3&gt;간단 요약&lt;/h3&gt;
&lt;p&gt;서버와 애플리케이션 사이 파이썬 웹 서버 게이트웨이 인터페이스&lt;/p&gt;
&lt;h3&gt;용어 정리&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;웹 서버 게이트웨이 인터페이스(WSGI, Web Server Gateway Interface)는 웹서버와 웹 애플리케이션의 인터페이스를 위한 파이썬 프레임워크다.&lt;br&gt;  WSGI는 처음에 2003년 PEP-333으로 규정되었다. 2010년에 출판된 PEP-3333은 파이썬 3을 위한 사양을 갱신한다.&lt;/li&gt;
&lt;li&gt;WSGI(Web Server Gateway Interface)는 웹 서버 소프트웨어와 파이썬으로 작성된 웹 응용 프로그램 간의 표준 인터페이스입니다. 표준 인터페이스는 여러 웹 서버에서 WSGI를 지원하는 응용 프로그램을 쉽게 사용할 수 있도록 합니다.개요&lt;ul&gt;
&lt;li&gt;환경변수가 바뀌면 타겟 URL에 따라서 리퀘스트의 경로를 지정해준다.&lt;/li&gt;
&lt;li&gt;같은 프로세스에서 여러 애플리케이션과 프레임워크가 실행되게 한다.&lt;/li&gt;
&lt;li&gt;XSLT 스타일시트를 적용하는 것과 같이 전처리를 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;애플리케이션 예시&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;def application(environ, start_response):
    start_response(&amp;#39;200 OK&amp;#39;, [(&amp;#39;Content-Type&amp;#39;, &amp;#39;text/plain&amp;#39;)])
    yield &amp;#39;Hello World\n&amp;#39;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;1번째 줄에서는 environ와 start_response를 매개변수를 가지는 callable을 선언하는데, environ은 환경변수를 가지고 있는 딕셔너리이고 start_response는 status와 response_headers를 가지는 callable이다.&lt;/li&gt;
&lt;li&gt;2번째 줄에서는 start_response를 호출한다.&lt;/li&gt;
&lt;li&gt;3번째 줄에서는 문자열을 리턴한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;애플리케이션 호출 예시&lt;/h5&gt;
&lt;p&gt;애플리케이션을 호출하고 리스폰스를 받는 예시이다&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
def call_application(app, environ):
    body = []
    status_headers = [None, None]
    def start_response(status, headers):
        status_headers[:] = [status, headers]
        return body.append(status_headers)
    app_iter = app(environ, start_response)
    try:
        for item in app_iter:
            body.append(item)
    finally:
        if hasattr(app_iter, &amp;#39;close&amp;#39;):
            app_iter.close()
    return status_headers[0], status_headers[1], &amp;#39;&amp;#39;.join(body)

status, headers, body = call_application(app, {...environ...})&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;WSGI는 서버와 게이트웨이, 애플리케이션과 프레임워크 양단으로 나눠져있다. WSGI 리퀘스트를 처리하려면, 서버단에서 환경정보와 콜백함수를 애플리케이션단에 제공해야한다. 애플리케이션은 그 요청을 처리하고 미리 제공된 콜백함수를 통해 서버단에 응답한다. WSGI 미들웨어(라고 불린다.)가 WSGI 서버와 애플리케이션 사이를 보충해주는데, 이 미들웨어는 서버의 관점에서는 애플리케이션으로, 애플리케이션의 관점에서는 서버로 행동한다. 이 미들웨어는 다음과 같은 기능을 가진다.&lt;/li&gt;
&lt;li&gt;기존의 파이썬 웹 애플리케이션 프레임워크는 웹서버를 선택하는데 있어서 제약이 있었다. 보통 CGI, FastCGI, mod_python 과 같은 커스텀API 중에 하나만 사용할 수 있도록 디자인 되었는데, WSGI는 그에 반하여 low-level로 만들어져서 웹서버와 웹 애플리케이션,프레임워크간의 벽을 허물었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;참고문헌&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%9B%B9_%EC%84%9C%EB%B2%84_%EA%B2%8C%EC%9D%B4%ED%8A%B8%EC%9B%A8%EC%9D%B4_%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4&quot;&gt;https://ko.wikipedia.org/wiki/웹_서버_게이트웨이_인터페이스&lt;/a&gt;&lt;br&gt;&lt;a href=&quot;https://docs.python.org/ko/3/library/wsgiref.html&quot;&gt;https://docs.python.org/ko/3/library/wsgiref.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.python.org/dev/peps/pep-0333/&quot;&gt;PEP 333 - Python Web Server Gateway Interface&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.archive.org/web/20060202222753/http://pythonpaste.org/&quot;&gt;WSGI metaframework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.wsgi.org/&quot;&gt;Comprehensive wiki about everything WSGI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.archive.org/web/20081204012403/http://webpython.codepoint.net/wsgi&quot;&gt;WSGI Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.python.org/library/wsgiref.html&quot;&gt;Python standard library module wsgiref&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://lucumr.pocoo.org/2007/5/21/getting-started-with-wsgi/&quot;&gt;Getting Started with WSGI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nwsgi.codeplex.com/&quot;&gt;NWSGI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>용어정리</category>
      <author>killog</author>
      <guid isPermaLink="true">https://etlwindy.tistory.com/16</guid>
      <comments>https://etlwindy.tistory.com/16#entry16comment</comments>
      <pubDate>Mon, 25 Oct 2021 01:13:12 +0900</pubDate>
    </item>
    <item>
      <title>데이터 마트/데이터 웨어하우스/데이터레이크</title>
      <link>https://etlwindy.tistory.com/14</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;데이터 소스&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터 웨어하우스 측면세어 업무 시스템을 위한 RDB 나 로그 등을 저장하는 파일 서버&lt;/li&gt;
&lt;li&gt;데이터 소스의 로우 데이터 (원시 데이터) 를 추출, 포맷팅을 위한 가공 후 데이터 웨어하우스에 저장하기 까지를 &lt;b&gt;ETL 프로세스&lt;/b&gt;라한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;데이터 웨어하우스&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;웹서버나 업무 시스템에서 이용되는 일반적인 RDB와는 달리, &quot;대량의 데이터를 장기 보존&quot; 하는 것에 최적화되어있다.&lt;/li&gt;
&lt;li&gt;데이터 레이크 (데이터 웨어하우스와 치환될 수 있다.)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터를 축적하는 호수에 비유되는 &quot;데이터 축적 장소&quot;&lt;/li&gt;
&lt;li&gt;모든 데이터를 원래의 형태로 축적하고, 그것을 필요에 따라 가공하는 구조&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;장점: 정리된 데이터를 한 번에 전송하는 것에 뛰어나다.&lt;/li&gt;
&lt;li&gt;단점:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;소량의 데이터를 자주 읽고 쓰는데 적합하지 않다.&lt;/li&gt;
&lt;li&gt;업무에 있어 중요한 데이터 처리에 사용되기 때문에 아무때나 함부로 사용해 시스템 과부하를 초래하면 안된다.`&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;데이터 마트&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터 분석과 같은 목적에 사용하는 경우, 데이터 웨어하우스에 필요한 데이터만 추출해 데이터 마트를 구축한다.&lt;/li&gt;
&lt;li&gt;데이터 마트는 BI 도구와 조합시키는 형태로 데이터를 시각화하는데에도 이용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고문헌&lt;br /&gt;빅데이터 지탱기술 16페이지&lt;/p&gt;</description>
      <category>용어정리</category>
      <author>killog</author>
      <guid isPermaLink="true">https://etlwindy.tistory.com/14</guid>
      <comments>https://etlwindy.tistory.com/14#entry14comment</comments>
      <pubDate>Sat, 23 Oct 2021 23:21:27 +0900</pubDate>
    </item>
    <item>
      <title>애드 혹 분석</title>
      <link>https://etlwindy.tistory.com/12</link>
      <description>&lt;ul style=&quot;list-style-type: disc;&quot; data-mark=&quot;*&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;애드혹은 또한 임시방편의 해결책, 불충분한 계획, 또는 즉석 이벤트라는 뜻을 함축하기도 한다. AdHoc, adhoc, ad-hoc 등으로 표기되기도 한다. (위키백과)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;임시 분석은 필요에 따라 데이터를 분석하는 원칙입니다. 이 분석은 분석을 수행하는 사람이 사용할 수있는 일련의 데이터를 기반으로합니다. 결과 분석은 기반이되는 데이터만큼만 우수합니다. 일반적으로이 프로세스는 특정 비즈니스 질문에 답변하는 데 사용됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;일회성 분석이라는 의미(빅데이터 지탱 기술 19p)&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-mark=&quot;*&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;애드혹 분석에서는 데이터 마트를 만들지 않은 채, 데이터 레이크와 데이터 웨어하우스에 직접 연결하는 경우가 많다. 이부분에 있어, 사용자는 작업하기 쉬운 환경을 선호한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;쿼리를 실행해 결과를 즉시 확인할 수 잇는 대화형 분석도구를 이용한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;어떤 데이터 분석이라도 처음에는 애드혹 분석에서 시작한다.(빅데이터 지탱 기술 64p)&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-mark=&quot;*&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;원하는 데이터가 어딨는지도 모르고, 집계 시간이 얼마나 걸리는지도 알 수 없는 상황에서 여러번의 시행착오를 번복하면서 데이터를 사용하는 것&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>용어정리</category>
      <author>killog</author>
      <guid isPermaLink="true">https://etlwindy.tistory.com/12</guid>
      <comments>https://etlwindy.tistory.com/12#entry12comment</comments>
      <pubDate>Sat, 23 Oct 2021 12:41:14 +0900</pubDate>
    </item>
  </channel>
</rss>