템플릿 저장하기


curl -XPOST 'http://127.0.0.1:9200/_search/template/blog-template' -d '
{
  "template": {
    "query": {
      "term": {
        "uuid": "{{value}}"
      }
    }
  }
}'


템플릿 보기

curl -XGET 'http://127.0.0.1:9200/_search/template/blog-template'
{"template":"{\"query\":{\"term\":{\"uuid\":\"{{value}}\"}}}"}


템플릿 삭제 

curl -XDELETE 'http://127.0.0.1:9200/_search/template/blog-template'
{"found":true,"_index":".scripts","_type":"mustache","_id":"blog-template","_version":2}

# 삭제되고 난 이후에 템플릿의 결과는 body가 없음.
curl -XGET 'http://127.0.0.1:9200/_search/template/blog-template'

(어떤 결과 없음)


# verbose로 보면 404 에러로 확인함

curl -v -XGET 'http://127.0.0.1:9200/_search/template/blog-template'

(404 에러)


Posted by '김용환'
,


일래스틱서치에서도 템플릿을 사용할 수 있다. 템플릿은 mustache (http://mustache.github.io/) 문법을 사용한다.


사용방법 


1. 템플릿을 저장한다.
(내부적으로 .scripts 색인에 저장된다. $elasticsearch_home$/config/scripts에 template.mustache 파일로 저장된다.)


curl -XPOST 'http://127.0.0.1:9200/_search/template/myTemplate' -d '

{

  "template": {

    "query": {

      "term": {

        "uuid": "{{value}}"

      }

    }

  }

}'





2. 템플릿을 사용한다. 


curl -XPOST 'http://127.0.0.1:9200/blog/comment/_search/template?pretty=true' -d '{

  "template": {

    "id": "myTemplate"

  },

  "params": {

    "value": "1234567"

  }

}'



* 참조

https://www.elastic.co/guide/en/elasticsearch/reference/1.4/query-dsl-template-query.html



Posted by '김용환'
,


일래스틱서치(elasticsearch)는 

grovy script 보안 이슈로 es 1.4.2 이하 버전의 디폴트 값은 true이고, 

1.4.3 이후 버전에서는 false로 되어 있다.


1.4.3 이후 버전에서 grovy script를 사용하려면 config/elasticsearch.yml 파일에 다음 설정을 추가한다.



script.groovy.sandbox.enabled: true




Posted by '김용환'
,



elasticsearch는 schema-less 아키텍처라 특정 필드가 존재하는지 확인할 필요가 있다. 

그 때는 exists 필터를 사용할 수 있다.  아래와 같이 요청하면 전체 다큐먼트 중, url 필드가 존재하는 다큐먼트를 검색한다. 


curl -XPOST 'http://127.0.0.1:9200/blog/comment/_search?pretty=true' -d '{

  "query": {

    "filtered": {

      "filter": {

        "exists": {

          "field":"url"

        }

      },

      "query": {

        "match_all": {}

      }

    }

  }

}'



exists 필터와 반대로 없는 것만 얻고 싶으면 missing 필터를 사용한다.


curl -XPOST 'http://127.0.0.1:9200/blog/comment/_search?pretty=true' -d '{

  "query": {

    "filtered": {

      "filter": {

        "missing": {

          "field":"url"

         }

       },

       "query": {

         "match_all": {}

       }

     }

  }

}'





exists와 missing 필터는 확인할 필드 이름으로 field 매개변수만을 받는다.

만약 임베디드 객체 또는 임베디드 객체의 목록을 사용하고 있다면, 하위 객체 필드를 같이 사용할 수 있다. 

Posted by '김용환'
,



https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html


https://www.found.no/foundation/function-scoring/


http://jontai.me/blog/2013/01/advanced-scoring-in-elasticsearch/

Posted by '김용환'
,



elasticsearch 1.4.2까지는 groovy script 사용 설정이 true 이었지만..



elasticsearch 1.4.3부터는 groovy script 사용 설정이 false이다.

만약 groovy script를 사용하려면 반드시 config/elasticsearch.yml에 다음 프로퍼티를 추가한다.


script.groovy.sandbox.enabled: true



Posted by '김용환'
,



일래스틱서치에서 특정 필드를 추가하려면 다음과 같이 매핑을 추가한다. 


* 필드 추가하기

curl -XPUT 'http://localhost:9200/blog/_mapping/comment' -d '
{
  "comment" : {
  "properties" : {
     "url" : {"type" : "string" }
    }
  }
}

'




* 필드 삭제하기

사실상 필드 삭제는 없다. 루씬의 색인 기능 때문에 따로 삭제가 불가능해서 새롭게 색인을 구성해야 한다. 전문용어로 reindex 이다.


그러나, 필드 삭제는 못하지만, 데이터만 삭제는 부분 변경(partial update)만으로 가능하다. 



* 추가된 필드에 데이터 저장하기


추가된 필드에 데이터를 저장하기 위해서 PUT http 메소드를 실행하면 기존 데이터는 덮어쓰인다. 따라서 이 부분은 부분 변경 (partial update)를 사용해야 한다.



아래와 같이 실행하면 기존 자료(_id 가 8130295인 데이터)는 사라진다. 즉 아래 데이터는 다큐먼트 데이터 변경 인 셈이다. 

curl -XPUT localhost:9200/blog/comment/8130295 -d '{
"url" : "m1"
}'



새롭게 추가된 필드에 데이터를 변경하려면 부분 변경(partial update)를 실행한다. 두 가지 방법이 있다.


1. _update 호출


curl -XPOST http://localhost:9200/blog/comment/8130295/_update -d '

{

   "doc" : {

       "url" : "http://www.google.com"

    }

}



2. 스크립트 기능 이용


curl -XPOST localhost:9200/blog/comment/8130295/_update -d '{
"script" : "ctx._source.url=new_url", "params" : { "new_url" : "................" }

}'


verion이 하나 추가된 다큐먼트 데이터가 생성된다. 확인은 다음과 같이 할 수 있다.


curl -XGET localhost:9200/blog/comment/8130295 




upsert 라는 것이 있는다. 해당 필드의 데이터의 값이 없다면 초기화값으로 넣을 수 있는 값이다. 


curl -XPOST http://localhost:9200/blog/comment/8130295/_update -d '

{

      "script" : "ctx._source.views+=1",

     "upsert": {

       "views": 1

    }

}



* 참고 

https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-put-mapping.html

https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-update.html

https://www.elastic.co/guide/en/elasticsearch/guide/current/partial-updates.html



Posted by '김용환'
,



select count(*) ... group by .. SQL 쿼리를 진행하려고 한다.

https://www.elastic.co/guide/en/elasticsearch/reference/1.5/_executing_aggregations.html

https://www.elastic.co/blog/intro-to-aggregations-pt-2-sub-aggregations

해결 방법은 두가지가 있다. 

- 일래스틱서치(elasticsearch)의 aggregation을 두 번 사용 (es 접속->agg요청/응답처리->es 연결 종료->es 접속 -> agg요청/응답처리->es 종료)

- 일래스틱서치(elasticsearch)의 subaggregation을 두 번 사용 (es 접속->sub agg요청/응답처리->es 연결 종료)




시간 소요 시간 테스트를 해보니. 35만건에 대해서 

aggreation을 두 번 사용하는 것은 2.6초

aggreation을 한 번 사용하는 것은 1.3초

걸렸다.


따라서, aggreation이 비싼 비용이기 때문에 aggregation을 sub aggregation을 추천한다!



자바 api 슈도 코드이다. aggreation 을 bucket으로 받아서 처리한 후,

bucket에서 aggregation을 얻어내서 처리하는 코드로 가능 (writer 개수 및 writer 정보도 다 얻어낼 수 있다.)


public List<Stat> getSubAggregation() {
List<Stat> stats = Lists.newArrayList();
QueryBuilder queryBuilder = QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(), null);

TermsBuilder subTermsAgg = AggregationBuilders.terms("aggs").field("writer")
.order(Terms.Order.count(false))
.size(1000000);

TermsBuilder termsAgg = AggregationBuilders.terms("aggs").field("id")
.order(Terms.Order.count(false))
.minDocCount(100)
.subAggregation(subTermsAgg)
.size(10000);

SearchRequestBuilder searchRequest = searchClient.prepareSearch(index).setTypes(type);
searchRequest.setQuery(queryBuilder).addAggregation(termsAgg);
SearchResponse response = searchRequest.execute().actionGet();

Terms terms = response.getAggregations().get("aggs");
for (Bucket bucket : terms.getBuckets()) {
Stat stat = new Stat();
Stat.Id = bucket.getKey();
Stat.totalCount = bucket.getDocCount();
Terms subTerms = bucket.getAggregations().get("aggs");

Map<String, Long> map = Maps.newHashMap();
for (Bucket subBucket : subTerms.getBuckets()) {
map.put(subBucket.getKey(), subBucket.getDocCount());
}
stat.uniqueWriter = map.size();
stats.add(stat);
}

return stats;
}




Posted by '김용환'
,




일래스틱서치는 검색보다 counting(개수 계산)이 빠르다. 결과가 필요하지 않는다면 counting(개수 계산)을 사용하는 것이 좋다.


개수 계산은 일래스틱서치에서 2가지 방식으로 구할 수 있다. 데이터를 수집하는 것보다 훨씬 자원(cpu, memory)을 적게 사용하므로 좋다.


http://www.elasticsearch.org/guide/reference/api/count/


https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-search-type.html



curl -XPOST http://localhost:9200/order/item/_count -d  {.. }



curl -XPOST http://localhost:9200/order/item/_search?search_type=count -d {.. }




Posted by '김용환'
,





 일래스틱서치 검색에는 두 개의 주요 개념인 질의(query)와 필터(filter)가 있다.


 질의(query)는 일치하는 결과가 내부 루씬의 득점 알고리즘 (scoring algorithm)기능을 이용하여  scoring하는 것을 의미한다.


필터(filter)는 score 없이 일치하는 결과만 가지고 결과를 얻는다.


따라서, 필터는 점수(scoring)을 계산할 필요가 없기 때문에 일반적으로 빠르고 캐시(cache)될 수 있다. 


필터를 일래스틱서치 문서에서 찾아보면서 cache 여부를 체크하며 보면 도움이 된다. 보통 cache 는 false로 되어 있다.



그러나, 전문 검색(full text query)일 때는 query가 월등히 빠르다.


참조

https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-filters.html

https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html

Posted by '김용환'
,