<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>단술의 잡다한 지식들</title>
    <link>https://triest.tistory.com/</link>
    <description>배우고 복습하기</description>
    <language>ko</language>
    <pubDate>Sat, 1 Aug 2026 12:43:14 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>홍규홍규</managingEditor>
    <image>
      <title>단술의 잡다한 지식들</title>
      <url>https://tistory1.daumcdn.net/tistory/2834778/attach/141a85108add49d4997cdb456f159a6e</url>
      <link>https://triest.tistory.com</link>
    </image>
    <item>
      <title>[7.17.x] CountRequest, CountResponse - 쿼리 카운트</title>
      <link>https://triest.tistory.com/55</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;#&amp;nbsp;Deprecated된&amp;nbsp;RestHighLevelClient를&amp;nbsp;대체하기&amp;nbsp;위해&amp;nbsp;ElasticsearchClient를&amp;nbsp;활용.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1666686069978&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static CountResponse getCountResponse(ElasticsearchClient client, Query query) {
  CountRequest countRequest = new CountRequest.Builder().query(query).build();
  try {
    return client.count(countRequest);
  } catch (IOException e) {
    e.printStackTrace();
  }
  return null;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 매개변수로 넘어오는 Query 객체는 MatchQuery, RangeQuery, BoolQuery 등.&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>
      <category>CountRequest</category>
      <category>CountResponse</category>
      <category>elasticsearch</category>
      <category>ElasticsearchClient</category>
      <author>홍규홍규</author>
      <guid isPermaLink="true">https://triest.tistory.com/55</guid>
      <comments>https://triest.tistory.com/55#entry55comment</comments>
      <pubDate>Tue, 25 Oct 2022 17:25:06 +0900</pubDate>
    </item>
    <item>
      <title>[7.17.x] ExistsRequest - 인덱스 존재여부 조회</title>
      <link>https://triest.tistory.com/54</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;# Deprecated된 RestHighLevelClient를 대체하기 위해 ElasticsearchClient를 활용.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1663057358863&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; ExistsRequest existsRequest = new ExistsRequest.Builder().index(index).build();
  try {
    BooleanResponse response = client.indices().exists(existsRequest);
    return response.value();
  } catch (IOException e) {
    return false;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 참고. 매개변수는 다음과 같이 List 또는 String 타입&lt;/p&gt;
&lt;pre id=&quot;code_1663057443539&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public final Builder index(List&amp;lt;String&amp;gt; list) {
  this.index = _listAddAll(this.index, list);
  return this;
}

public final Builder index(String value, String... values) {
  this.index = _listAdd(this.index, value, values);
  return this;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>엘라스틱서치</category>
      <category>elasticsearch</category>
      <category>ElasticsearchClient</category>
      <category>ExistsRequest</category>
      <author>홍규홍규</author>
      <guid isPermaLink="true">https://triest.tistory.com/54</guid>
      <comments>https://triest.tistory.com/54#entry54comment</comments>
      <pubDate>Tue, 13 Sep 2022 17:26:29 +0900</pubDate>
    </item>
    <item>
      <title>[7.17.x] 새로워진 Client 빈 생성하고 사용하기</title>
      <link>https://triest.tistory.com/53</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;# Deprecated된 RestHighLevelClient를 대체하기 위해 ElasticsearchClient를 활용.&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;1. 버전 확인. (버전별 호환은 아래 사이트에서 확인할 수 있다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(&lt;a href=&quot;https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#core.extensions&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#core.extensions&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;173&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6AY5o/btrL5b8fwLs/wcQf9RLzSErKFafeOp4Hgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6AY5o/btrL5b8fwLs/wcQf9RLzSErKFafeOp4Hgk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6AY5o/btrL5b8fwLs/wcQf9RLzSErKFafeOp4Hgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6AY5o%2FbtrL5b8fwLs%2FwcQf9RLzSErKFafeOp4Hgk%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;962&quot; height=&quot;173&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;173&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;2. 스프링부트 2.7.3 기준&lt;/p&gt;
&lt;pre id=&quot;code_1663056891272&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  implementation 'org.springframework.boot:spring-boot-starter-data-elasticsearch'
  // 빈 생성 에러가 발생할 경우 아래도 추가해준다.
  implementation 'jakarta.json:jakarta.json-api:2.1.1'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. Configuration 클래스에 Bean 추가&lt;/p&gt;
&lt;pre id=&quot;code_1663056813286&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Bean
public ElasticsearchClient esClient() {
  RestClient restClient = RestClient.builder(new HttpHost(&quot;url&quot;, 9200)).build();
  ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
  return new ElasticsearchClient(transport);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>엘라스틱서치</category>
      <category>elasticsearch</category>
      <category>ElasticsearchClient</category>
      <author>홍규홍규</author>
      <guid isPermaLink="true">https://triest.tistory.com/53</guid>
      <comments>https://triest.tistory.com/53#entry53comment</comments>
      <pubDate>Tue, 13 Sep 2022 17:20:46 +0900</pubDate>
    </item>
    <item>
      <title>IntelliJ xml 쿼리문에 녹색 배경이 깔리는 현상</title>
      <link>https://triest.tistory.com/52</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;IntelliJ의 경우 MyBatis 연동을 하면 쿼리문의 배경이 아래처럼 적용되는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Injected language fragment 가 설정됐기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;656&quot; data-filename=&quot;inelli_01.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7hK6y/btq6jklkeFS/b1kH9MZRXmSNZag0qb6eUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7hK6y/btq6jklkeFS/b1kH9MZRXmSNZag0qb6eUK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7hK6y/btq6jklkeFS/b1kH9MZRXmSNZag0qb6eUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7hK6y%2Fbtq6jklkeFS%2Fb1kH9MZRXmSNZag0qb6eUK%2Fimg.png&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;656&quot; data-filename=&quot;inelli_01.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;File - Settings - Editor - Color Scheme - General에 보면 다음과 같이 Background에 체크돼있는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 체크해제 하면 배경이 사라지면서 깔끔해진다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;432&quot; data-filename=&quot;inelli_02.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bk1JAk/btq6ll4SJ6U/9SRikWxvoKIda4pKwhDoMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bk1JAk/btq6ll4SJ6U/9SRikWxvoKIda4pKwhDoMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bk1JAk/btq6ll4SJ6U/9SRikWxvoKIda4pKwhDoMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbk1JAk%2Fbtq6ll4SJ6U%2F9SRikWxvoKIda4pKwhDoMk%2Fimg.png&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;432&quot; data-filename=&quot;inelli_02.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;- 이상 끗.&lt;/p&gt;</description>
      <category>Java &amp;amp; Spring</category>
      <author>홍규홍규</author>
      <guid isPermaLink="true">https://triest.tistory.com/52</guid>
      <comments>https://triest.tistory.com/52#entry52comment</comments>
      <pubDate>Tue, 1 Jun 2021 15:40:12 +0900</pubDate>
    </item>
    <item>
      <title>2년만에 찾은 폐가 ..</title>
      <link>https://triest.tistory.com/51</link>
      <description>&lt;p&gt;2년만에 폐가처럼 되어버린 블로그를 다시 방문하였는데,&lt;/p&gt;
&lt;p&gt;웬 걸 여전히 깔끔하고 정돈되어있다. 핫핫.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;바쁘고 귀찮다는 핑계로 소홀히 하였으나&lt;/p&gt;
&lt;p&gt;다시 시작해볼까 한다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그동안 공부하고 배웠던 것들 다 블로깅 했으면 참 많은 데이터가&lt;/p&gt;
&lt;p&gt;쌓였을 텐데, 돌이켜보니 넘나 아쉬운 것.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이제부터라도 다시 시작하는 마음으로.&lt;/p&gt;</description>
      <category>잡담</category>
      <author>홍규홍규</author>
      <guid isPermaLink="true">https://triest.tistory.com/51</guid>
      <comments>https://triest.tistory.com/51#entry51comment</comments>
      <pubDate>Fri, 26 Feb 2021 10:27:07 +0900</pubDate>
    </item>
    <item>
      <title>인텔리J 스프링부트, MyBatis CamelCase 적용하기</title>
      <link>https://triest.tistory.com/50</link>
      <description>&lt;p&gt;# 작업환경 IntelliJ, SpringBoot 2.4.3, gradle 기반, Java 13&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;# TEST_ID -&amp;gt; testId 형식의&amp;nbsp; CamelCase 적용하기&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;기존 레거시에서는 ObjectMapperFactory 구현과 MapWrapper 상속을 이용해서&lt;/p&gt;
&lt;p&gt;hashmap에 들어간 key를 바꾸는 방법을 사용했는데 부트에서는 좀 더 다른 방법을 써보기로 했다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;다만, 아래와 같은 방법으로 하면 resultType을 hashmap이 아닌 구현한 객체 이름으로 바꿔줘야 한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;1. 내가 사용한 방법은 guava 라이브러리를 활용, 따라서 build.gradle에 해당 라이브러리를 등록했다.&lt;/p&gt;
&lt;pre id=&quot;code_1614302034699&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dependencies {
    // ...
    implementation group: 'com.google.guava', name: 'guava', version: '30.1-jre'
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;2. mybatis-config.xml 작성하기&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1614301403745&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;!DOCTYPE configuration PUBLIC &quot;-//mybatis.org//DTD Config 3.0//EN&quot; &quot;http://mybatis.org/dtd/mybatis-3-config.dtd&quot;&amp;gt;
&amp;lt;configuration&amp;gt;
  &amp;lt;typeAliases&amp;gt;
    &amp;lt;typeAlias type=&quot;packagename.mybatis.CamelHashMap&quot; alias=&quot;CamelHashMap&quot; /&amp;gt;
  &amp;lt;/typeAliases&amp;gt;
&amp;lt;/configuration&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;- 기타 설정은 필요없어서 날리고 생성할 객체만 typeAlias로 지정해주었다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;3. application.properties 에 mybatis-config.xml 등록하기&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-filename=&quot;camel_01.png&quot; data-origin-width=&quot;253&quot; data-origin-height=&quot;144&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lTmSU/btqYtO3edXV/35nzO6ckBEf3e9kETS3iAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lTmSU/btqYtO3edXV/35nzO6ckBEf3e9kETS3iAk/img.png&quot; data-alt=&quot;mybatis-config.xml 의 위치&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lTmSU/btqYtO3edXV/35nzO6ckBEf3e9kETS3iAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlTmSU%2FbtqYtO3edXV%2F35nzO6ckBEf3e9kETS3iAk%2Fimg.png&quot; data-filename=&quot;camel_01.png&quot; data-origin-width=&quot;253&quot; data-origin-height=&quot;144&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;mybatis-config.xml 의 위치&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;파일의 경로를 아래와 같이 등록했다.&lt;/p&gt;
&lt;pre id=&quot;code_1614301913437&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Mybatis
mybatis.config-location=classpath:mybatis/mybatis-config.xml&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;4. CamelHashMap 클래스 생성 및 기능 구현&lt;/p&gt;
&lt;pre id=&quot;code_1614302135760&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class CamelHashMap extends HashMap&amp;lt;String, Object&amp;gt; {
  public Object put(String key, Object value) {
    return super.put(CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, key), value);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;5. 결과&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-filename=&quot;camel_02.png&quot; data-origin-width=&quot;557&quot; data-origin-height=&quot;143&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bp2VuQ/btqYE61QHwa/h7tEWTL3Kn75kXKWfvNOSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bp2VuQ/btqYE61QHwa/h7tEWTL3Kn75kXKWfvNOSk/img.png&quot; data-alt=&quot;ABC_DE가 abcDe의 형태로 변환된 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bp2VuQ/btqYE61QHwa/h7tEWTL3Kn75kXKWfvNOSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbp2VuQ%2FbtqYE61QHwa%2Fh7tEWTL3Kn75kXKWfvNOSk%2Fimg.png&quot; data-filename=&quot;camel_02.png&quot; data-origin-width=&quot;557&quot; data-origin-height=&quot;143&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;ABC_DE가 abcDe의 형태로 변환된 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;※ varchar의 결과가 위와 같이 byte 형식으로 반환된 것은 마리아db의 버전이 낮아서일까.. (10.1.x)&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 10.4.x에서는 정상적인 문자열로 반환이 된다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 위 경우 byte 를 String 형태로 다시 변환하는 작업을 해야 하는데, 그냥 vo를 사용할까 싶다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; (해결 방법을 도저히 찾을 수가 없음)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;- 이상 끗&lt;/p&gt;</description>
      <category>Java &amp;amp; Spring</category>
      <category>camelCase</category>
      <category>IntelliJ</category>
      <category>myBatis</category>
      <category>SpringBoot</category>
      <category>스프링부트</category>
      <category>인텔리J</category>
      <category>인텔리제이</category>
      <author>홍규홍규</author>
      <guid isPermaLink="true">https://triest.tistory.com/50</guid>
      <comments>https://triest.tistory.com/50#entry50comment</comments>
      <pubDate>Fri, 26 Feb 2021 10:21:06 +0900</pubDate>
    </item>
    <item>
      <title>우분투(18.04)에 openjdk 11 설치하기</title>
      <link>https://triest.tistory.com/48</link>
      <description>&lt;p&gt;1. 기존에 오라클 또는 openjdk 구 버전이 설치되어있다면 다 삭제한다.&lt;/p&gt;&lt;p&gt;- openjdk-java 시리즈&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;xml&quot;&gt;# sudo apt-get remove openjdk*&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;- oracle-java 시리즈&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;xml&quot;&gt;# sudo apt-get remove oracle*&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;- 완료하고 나면 다음 명령어도 실행해주자.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;xml&quot;&gt;# sudo apt-get autoremove --purge
$ sudo apt-get autoclean&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2. oepnjdk 설치&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;xml&quot;&gt;# sudo apt install openjdk-11-jdk &lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;이렇게 설치하고 나서 자바 버전을 확인해보면 다음과 같이 나온다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;xml&quot;&gt;# sudo apt install openjdk-11-jdk
# java -version
openjdk version &quot;10.0.2&quot; 2018-07-17
OpenJDK Runtime Environment (build 10.0.2+13-Ubuntu-1ubuntu0.18.04.4)
OpenJDK 64-Bit Server VM (build 10.0.2+13-Ubuntu-1ubuntu0.18.04.4, mixed mode)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;????&lt;/p&gt;&lt;p&gt;분명 11 설치했는데???&lt;/p&gt;&lt;p&gt;이것에 대한 이유는 다음 사이트에 가보면 대략 알 수 있다.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://askubuntu.com/questions/1037646/why-is-openjdk-10-packaged-as-openjdk-11&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;https://askubuntu.com/questions/1037646/why-is-openjdk-10-packaged-as-openjdk-11&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그럼 실제 openjdk를 설치하려면 어떡해야 되지?&amp;nbsp;&lt;/p&gt;&lt;p&gt;다음과 같은 방법으로 설치하자.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;xml&quot;&gt;# sudo add-apt-repository ppa:openjdk-r/ppa
# sudo apt install openjdk-11-jdk&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;자바11에 새롭게 도입된 String 클래스의 strip(), lines(), 또는 Collection에 새롭게 추가된 toArray()나 incubator에서 나온&lt;/p&gt;&lt;p&gt;HttpClient 같은 클래스를 사용하여 빌드할 땐 문제가 되기 때문에 11 버전으로 제대로 설치해줘야 한다.&lt;/p&gt;&lt;p&gt;성공적으로 설치가 된다면 다음과 같이 제대로 출력됨을 볼 수 있다. &lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;xml&quot;&gt;# java -version
openjdk version &quot;11.0.1&quot; 2018-10-16
OpenJDK Runtime Environment (build 11.0.1+13-Ubuntu-3ubuntu118.04ppa1)
OpenJDK 64-Bit Server VM (build 11.0.1+13-Ubuntu-3ubuntu118.04ppa1, mixed mode, sharing)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;- 이상 끗~!&lt;/p&gt;</description>
      <category>Java &amp;amp; Spring</category>
      <author>홍규홍규</author>
      <guid isPermaLink="true">https://triest.tistory.com/48</guid>
      <comments>https://triest.tistory.com/48#entry48comment</comments>
      <pubDate>Wed, 27 Mar 2019 13:59:05 +0900</pubDate>
    </item>
    <item>
      <title>Type is deprecated in 6.0</title>
      <link>https://triest.tistory.com/47</link>
      <description>&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;- Elasticsearch에서 제공하는 Type이 deprecated 되었습니다. 그것도 모르고 여태 써왔다니!!&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&amp;nbsp; 보통 RDB의 Table과 매칭시켜서 설명을 많이 했는데 deprecated된 김에 자세히 좀 들여다보았습니다.&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 452px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/995922405C749CF608&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F995922405C749CF608&quot; width=&quot;452&quot; height=&quot;224&quot; filename=&quot;elastic_02.jpg&quot; filemime=&quot;image/jpeg&quot; style=&quot;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;6.0 이전까지는 하나의 Index에 복수의 Type을 지정해서 사용하는 것이 가능했습니다.&amp;nbsp;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;마치 RDB의 Table처럼. 그리고 그 안에는 또 Document들이 저장되었습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;하지만 엄격히 말하면 Elasticsearch의 Type은 RDB의 Table과는 다릅니다.&lt;/p&gt;&lt;p&gt;Table의 경우 A라는 Table에 있는 name과&amp;nbsp;B라는 Table에 있는 name은 독립적이고 서로에게 아무런&amp;nbsp;&lt;/p&gt;&lt;p&gt;영향도 끼치지 않지만 Type의 경우엔 그렇지 않습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;A라는 Type의 name Field와&amp;nbsp;B라는 Type의 name Field는 내부적으로는 같은 루씬 Field를 사용합니다.&lt;/p&gt;&lt;p&gt;즉 두 Type의 name Field 모두 동일한 루씬 Field에 저장되며 두 Type 모두에서 동일한 mapping을 가집니다.&lt;/p&gt;&lt;p&gt;따라서 다른 Type의 동일한 Field는 서로 관련이 있게 되고, 이것이 내부적으로 몇 가지 문제를&lt;/p&gt;&lt;p&gt;야기할 가능성이 있다고 합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그래서 6.0에서 deprecated되고 7.0부터는 아예 삭제가 되어 Type과 관련된 기능은 사용할 수 없게 됩니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;중요한 것은 instead of, 즉 대안이 없습니다. 그냥 사용하면 안 됩니다.&lt;/p&gt;&lt;p&gt;7.0부터는 모든 Index는 단 하나의 Type(_doc)만을 가지게 됩니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;따라서 Type으로 나누던 데이터 저장 방법을 Index로 나누는 걸로 변경해야 합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;혹시 더 좋은 방법 있으면 공유 좀...&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;- 관련 레퍼런스&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.elastic.co/guide/en/elasticsearch/reference/master/removal-of-types.html&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;https://www.elastic.co/guide/en/elasticsearch/reference/master/removal-of-types.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;- deprecated list&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://artifacts.elastic.co/javadoc/org/elasticsearch/client/elasticsearch-rest-high-level-client/7.0.0-alpha2/deprecated-list.html&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;https://artifacts.elastic.co/javadoc/org/elasticsearch/client/elasticsearch-rest-high-level-client/7.0.0-alpha2/deprecated-list.html&lt;/a&gt;&lt;/p&gt;</description>
      <category>엘라스틱서치</category>
      <author>홍규홍규</author>
      <guid isPermaLink="true">https://triest.tistory.com/47</guid>
      <comments>https://triest.tistory.com/47#entry47comment</comments>
      <pubDate>Tue, 26 Feb 2019 11:09:35 +0900</pubDate>
    </item>
    <item>
      <title>리눅스에 Elasticsearch 설치하기</title>
      <link>https://triest.tistory.com/46</link>
      <description>&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;1. 설치 환경&lt;/p&gt;&lt;p&gt;&amp;nbsp;- CentOS Linux 7 (release 7.3.1611)&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;2. Elasticsearch 다운로드 및 설치&lt;/p&gt;&lt;p&gt;&amp;nbsp;- Elasticsearch는 root계정으로는 실행할 수 없다. 따라서 계정을 추가하고 해당 계정으로 설치하고 실행해야 한다.&lt;/p&gt;&lt;p&gt;&amp;nbsp;-&amp;nbsp;&lt;a href=&quot;https://www.elastic.co/kr/downloads/elasticsearch&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;https://www.elastic.co/kr/downloads/elasticsearch&lt;/a&gt; 사이트 접속 후 MACOS/LINUX 의 링크 주소를 복사한다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp;(현재 버전 6.6.1)&lt;/p&gt;&lt;p&gt;&amp;nbsp;- 리눅스 서버에 로그인하고 Elasticsearch를 다운받는다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;xml&quot;&gt;# wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.6.0.tar.gz&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&amp;nbsp;- root가 아닌 계정으로는 rpm을 통해 설치할 수 없으므로 위처럼 wget 명령어를 사용한다.&lt;/p&gt;&lt;p&gt;&amp;nbsp;- 다운로드 후에는 다음 명령어를 통해 압축을 푼다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;xml&quot;&gt;# tar xvzf elasticsearch-6.6.0.tar.gz&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;압축이 풀리고 나면 실행할 수가 있는데, 로컬이 아닌 외부에서 서버로 접속할 수 있도록 ip와 port를 열어줘야 한다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;3. 방화벽 해제 후 ip와 port open&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;xml&quot;&gt;# firewall-cmd --permanent --zone=public --add-port=9200/tcp
# firewall-cmd --reload
# firewall-cmd --list-ports&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;- Elasticsearch의 config폴더로 이동 후에 elasticsearch.yml을 편집합니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;xml&quot;&gt;# cd elasticsearch-6.6.0/config/
# vi elasticsearch.yml&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;- i를 눌러 편집모드로 전환한 후에 http.port 부분을 찾아서 주석을 해제하고 다음과 같이 설정한다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 370px; text-align: center;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99A8F2495C736F882F&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99A8F2495C736F882F&quot; width=&quot;370&quot; height=&quot;92&quot; filename=&quot;elastic.jpg&quot; filemime=&quot;image/jpeg&quot; style=&quot;text-align: center;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;- http.host 에는 해당 리눅스의 서버 ip를 작성하면 된다.&lt;/p&gt;&lt;p&gt;&amp;nbsp;- 수정이 완료되었으면 Esc를 눌러 편집모드에서 빠져나온 후 :wq 를 입력해 저장하고 나온다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;4. Elasticsearch 실행&lt;/p&gt;&lt;p&gt;&amp;nbsp;- bin 폴더로 이동한 후 ./elasticsearch 를 입력하면 로그가 뜨면서 정상적으로 실행이 된다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;5. 테스트&lt;/p&gt;&lt;p&gt;&amp;nbsp;- 다음 화면과 같이 정상적으로 접속됨을 확인할 수 있다.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&amp;nbsp;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 478px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F46B4B5C73708933&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F46B4B5C73708933&quot; width=&quot;478&quot; height=&quot;348&quot; filename=&quot;elastic2.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;</description>
      <category>엘라스틱서치</category>
      <author>홍규홍규</author>
      <guid isPermaLink="true">https://triest.tistory.com/46</guid>
      <comments>https://triest.tistory.com/46#entry46comment</comments>
      <pubDate>Mon, 25 Feb 2019 13:39:08 +0900</pubDate>
    </item>
    <item>
      <title>Bulk Api를 활용하여 Elasticsearch에 대량 데이터 인덱스하기</title>
      <link>https://triest.tistory.com/45</link>
      <description>&lt;p&gt;해당 포스트는 다음 링크의 포스트를 참고하여 작성한 것입니다.&lt;/p&gt;
&lt;p&gt;[&lt;a href=&quot;https://www.compose.com/articles/compose-elasticsearch-bulk-uploading-and-the-high-level-java-rest-client-part-1/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;바로가기&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이 포스트에서는 Bulk Api와 High-Level-Rest-Client를 활용하여 Elasticsearch에 대량의 데이터를&amp;nbsp;&lt;/p&gt;
&lt;p&gt;업로드하는 방법을 소개합니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;※ Elasticsearch는 5.6.0 버전에서 Rest Client를 Low-Level과 High-Level 두 가지로 분리시켰습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp;Transport Client는 7.0에서 deprecated되었으며 8.0에서는 삭제시킬 예정이라고 합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp;이 글에서는 Low-Level-Rest-Client와 Hight-Level-Rest-Client의 차이점에 대한 내용은 생략합니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;데이터는 JSON 파일이고 Elasticsearch에 업로드되는 과정은 다음과 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;사내 서버에서 1시간 마다 로그 파일 생성 -&amp;gt; 스프링 스케쥴러를 이용해 매 시간마다 해당 로그 파일을 로드&lt;/p&gt;
&lt;p&gt;-&amp;gt; 해당 로그파일을 파싱하지 않고 바로 Bulk Api를 사용해 Elasticsearch에 PUT&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;0. 시스템 환경&lt;/p&gt;
&lt;p&gt;- Spring Boot 2.1.2 RELEASE&lt;/p&gt;
&lt;p&gt;- Spring webflux&lt;/p&gt;
&lt;p&gt;- JAVA 8&lt;/p&gt;
&lt;p&gt;- Elasticsearch 6.6.0&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;1. JSON 파일 준비&lt;/p&gt;
&lt;p&gt;- Bulk API를 사용하기 위해서는 줄바꿈 형식의 데이터셋이 필요합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 즉, 마지막 행을 비롯하여 모든 행의 끝에는 개행문자가 있어야 합니다.(\n)&lt;/p&gt;
&lt;p&gt;&amp;nbsp; 예를 들면 다음과 같습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;json&quot;&gt;{ &quot;data&quot; : &quot;1&quot; }
{ &quot;data&quot; : &quot;2&quot; }
...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;2. BulkProcessor vs BulkRequestBuilder&lt;/p&gt;
&lt;p&gt;- 이 포스트에서는 BulkRequest를 사용합니다. 원글에서는 두 가지 모두를 사용한 예제가 있습니다.&lt;/p&gt;
&lt;p&gt;- 둘의 차이점은 다음 링크에서 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; [&lt;a href=&quot;https://stackoverflow.com/questions/45207887/what-is-the-difference-between-bulkprocessor-and-bulkrequestbuilder-elasticsea&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;바로가기&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;3. application.properties&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;elasticsearch.host=127.0.0.1
elasticsearch.port=9200&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;4. Elasticsearch Config 파일 작성&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- RestHighLevelClient를 Bean으로 등록해 필요할 때마다 꺼내쓸 수 있도록 합니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;java&quot;&gt;@Configuration
public class ElasticSearchConfig {
  @Value(&quot;${elasticsearch.host}&quot;)
  private String host;
  
  @Value(&quot;${elasticsearch.port}&quot;)
  private int port;

  @Bean
  public RestHighLevelClient getRestClient() {
    RestClientBuilder builder = RestClient.builder(new HttpHost(host, port, &quot;http&quot;));
    return new RestHighLevelClient(builder);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;5. Shceduler 작성&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 스케쥴러를 사용하기 위해서는 별도의 Bean을 등록해야 하므로 프로젝트 Application에 추가합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- @EnableScheduling 어노테이션을 명시하지 않을 경우 어플리케이션은 시작과 동시에 종료됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 예제는 단일쓰레드이며 쓰레드 풀이 필요하다면 ThreadPoolTaskScheduler를 사용하면 됩니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;java&quot;&gt;@SpringBootApplication
@EnableScheduling
public class ExampleApplication {

  public static void main(String[] args) {
    SpringApplication.run(ExampleApplication.class, args);
  }

  // 추가된 부분
  @Bean
  public TaskScheduler taskScheduler() {
    return new ConcurrentTaskScheduler();
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;6. Sheduler&amp;nbsp;작성&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;java&quot;&gt;@Component
public class ExampleScheduler {
  @Autowired ExampleService exampleService;

  @Scheduled(cron=&quot;15 0 * * * *&quot;)
  public void getJSONFileFromServer() throws IOException {
    // 파일은 &quot;년-월-일-시&quot;의 형식으로 생성
    Date date = new Date();
    SimpleDateFormat format = new SimpleDateFormat(&quot;YYYY-MM-dd-HH&quot;); 
    requestIndexToElasticFromJsonFile(format.format(date));
  }

  private void requestIndexToElasticFromJsonFile(String fileName) {
    File file = new File(&quot;서버파일경로&quot; + fileName);
    if(!file.isFile()) { // 파일이 아직 생성되지 않았다면
      fileCheckWithTimer(fileName);
      return;
    }
    exampleService.bulkToElasticsearch(fileName);
  }

  private void fileCheckWithTimer(String fileName) {
    File file = new File(&quot;서버파일경로&quot; + fileName);
 
    Timer timer = new Timer();
    TimerTask timerTask = new TimerTask() {
      int count = 0;
      @Override
      public void run() {
        if(file.isFile()) {
          timer.cancel();
          try {
            exampleService.bulkToElasticsearch(fileName);
          } catch(IOException e) { 
            e.printStackTrace();
          }
        } else if(!file.isFile() &amp;amp;&amp;amp; count == 58) {
          // 1시간이 지나도록 파일이 생성되지 않으면 다음 파일 작업을 위해 중단
          timer.cancel();
        } else
          System.out.println(&quot;File &quot; + fileName + &quot; is searching&quot;);
        count++;
      }
    };
    timer.schedule(timerTask, 0, 60000); // 1분마다 
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;7. ServiceImpl 작성&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;java&quot;&gt;@Component
public class ExampleServiceImpl implements ExampleService {
  @Autowired RestHighLevelClient restHighLevelClient;
  
  ...

  public void bulkToElasticsearch(String fileName) thorws IOException {
    String filePath = &quot;서버파일경로&quot; + fileName;
    File file = new File(filePath);
    BulkRequest bulkRequest = new BulkRequest();

    int id = 0; // id를 함께 인덱스하기 위한 시작값 생성
    int batch = 1000; 
    String line;

    BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), &quot;UTF-8&quot;));

    while((line = br.readLine()) != null) {
      // json 파일을 행 단위로 읽는 족족 IndexRequest에 담는다.
      IndexRequest indexRequest = new IndexRequest(&quot;index&quot;, fileName, id + &quot;&quot;);
      indexRequest.source(line, XContentType.JSON);
      bulkRequest.add(indexRequest);

      if(id % batch == 0) { // 1000개가 넘을 경우 1000 단위로 인덱스한다.
        BulkResponose bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        if(bulkResponse.hasFailures()) {
          for(BulkItemResponse bulkItemResponse : bulkResponse) {
            if(bulkItemResponse.isFailed()) {
              BulkItemResponse.Failure failure = bulkItemResponse.getFailure();
              System.out.println(&quot;Error : &quot; + failure.toString());
            }
          }
        }
        System.out.println(&quot;Uploaded bulk id : &quot; + id);
        bulkRequest = new BulkRequest();
      }
      id++;
    }

    if(bulkRequest.numberOfActions() &amp;gt; 0) {
      // 코드가 반복되므로 차후 리팩토링
      BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
      if(bulkResponse.hasFailures()) {
        for(BulkItemResponse bulkItemResponse : bulkResponse) {
          if(bulkItemResponse.isFailed()) {
            BulkItemResponse.Failure failure = bulkItemResponse.getFailure();
            System.out.println(&quot;Error : &quot; + failure.toString());
          }
        }
      }
    }
    System.out.println(&quot;Total uploaded : &quot; + id);
    restHighLevelClient.close();
    br.close();
  }

  ...

}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;8. 결과&lt;/p&gt;&lt;p&gt;&amp;nbsp;- 다음과 같이 1938개의 도큐먼트를 1000개 단위로 엘라스틱서치에 업로드하는 것을 성공했습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 297px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99FB0E505C6620720C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99FB0E505C6620720C&quot; width=&quot;297&quot; height=&quot;74&quot; filename=&quot;벌크.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;9. 기타&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&amp;nbsp;- BulkProcessor를 사용하면 자동으로 문서 단위로 벌크 업로드를 해주는 거 같습니다. 이건 다음에...;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&amp;nbsp;- builder를 생성하고 builder 옵션을 통해 설정할 수 있는데 기본 값은 1000개의 도큐먼트 단위, 5MB의 크기,&amp;nbsp;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&amp;nbsp; &amp;nbsp;1개의 동시 요청 등이 있습니다. 기본 옵션만으로도 BulkProcessor가 알아서 벌크 업로드를 하는 듯 합니다.&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&amp;nbsp;- BulkProcessor의 기능도 익히고 나면 이게 더 나은 선택이 될 수도 있겠습니다.&amp;nbsp;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&amp;nbsp;- 일단 사내 테스트 용으로 생성된 파일이 단위당 1200만건 정도니, 파일을 확보 후에&amp;nbsp;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&amp;nbsp; &amp;nbsp;BulkRequest와 BulkProcessor 둘 다 테스트 후 사용하는 것이 좋을 듯 하네요.&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;이상으로 Elasticsearch 6.6.0 및 Bulk Api와&amp;nbsp;Spring Boot를 활용한 대량 데이터 업로드 예제를 마치겠습니다.&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;수고했어 김과장~&lt;/p&gt;&lt;p style=&quot;text-align: left;&quot;&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>엘라스틱서치</category>
      <author>홍규홍규</author>
      <guid isPermaLink="true">https://triest.tistory.com/45</guid>
      <comments>https://triest.tistory.com/45#entry45comment</comments>
      <pubDate>Wed, 13 Feb 2019 17:44:45 +0900</pubDate>
    </item>
  </channel>
</rss>