SQL 시작
69594 단어 JavaSQLElasticsearchtech
이마
SQL 좋아하세요?처음에 글을 쓰는 것은두번째이지만, 나는 SQL을 완전히 이해하지 못해서 좋아하게 되었다.
이번 기고문에는 SQL에서 Elaticsearch를 요청할 수 있는 Elastic사 공식 플러그인Elasticsearch SQL이 소개된다.
지난번 보도와는 다르다
저번 보도에서도 Elasticsearch에 SQL을 발매하고 요청하는 방법을 소개했는데 그것은 Open Distro for Elasticsearch의 플러그인이다.양자의 커다란 차이는 다음과 같다.
Elasticsearch SQL
Open Distor for Elasticsearch SQL
라이선스
Elastic License (Basic Subscription) [1]
Apache License
잇닿다
JDBC, ODBC
JDBC, ODBC
GUI
×
Query Workbench
CLI
○
○
DSL로 변환
○(translate API)
○ (explain API)
Elasticsearch SQL에 대한 제한 사항
Elasticsearch SQL은 다양한 제한이 있고 SQL Limitations 페이지에 일람된 기록이 있다.
2020년 12월 12일 비교적 중요한 것에 뽑혔다면 다음과 같은 몇 가지를 열거할 수 있다.
Elatic License Edition 컨테이너 실행
검증된 환경 구축을 위해docker-compose를 사용합니다.주요 환경은 다음과 같다.
릴리즈
mac OS
10.15.7
docker for mac
2.4.0.0
Elaticsearch
7.10.0
Kibana
7.10.0
또한 이번 검증에는 키바나가 처음 시작될 때 기본적으로 설정할 수 있는 Sample eCommerce orders 데이터 세트가 사용됩니다.
docker-compose.준비
이번에 준비한 검증용 클러스터의 구성은 다음과 같다.특별히 여러 대를 구성할 필요가 없기 때문에 싱글 노드다.
docker-compose.yml
version: '2.2'
services:
es01:
image: docker.elastic.co/elasticsearch/elasticsearch:7.10.0
container_name: es01
environment:
- node.name=es01
- discovery.seed_hosts=es02
- cluster.initial_master_nodes=es01
- cluster.name=docker-cluster
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms256m -Xmx256m"
ulimits:
memlock:
soft: -1
hard: -1
ports:
- 9200:9200
networks:
- esnet
kibana:
image: docker.elastic.co/kibana/kibana:7.10.0
links:
- es01:elasticsearch
ports:
- 5601:5601
networks:
- esnet
environment:
- xpack.monitoring.ui.container.elasticsearch.enabled=true
networks:
esnet:
이때의 주의점으로 docker 그림 *-oss
을 주지 않은 것을 사용하십시오.현재 Elatic사가 공식적으로 공개한 도커 이미지는 아파치 라이선스에서 사용할 수 있는 Elasticsearch-Soss와 Elastic 라이선스에서 사용할 수 있는 두 가지 기능으로 나뉜다.
elasticsearch | Docker
이번에 사용하고자 하는 기능은 앞서 설명한 대로 Elastic 라이센스 아래에 있는 기능이므로 후자의 기능을 명시적으로 지정합니다.
실천하다
전권을 던져 조회를 얻으려 하다
우선 획득한 SQL을 모두 던져보자.
Kibana&Dev Tools에서 요청 실행 화면을 표시합니다.
▼ Dev Tools
던지기 질의는 일반 SELECT*입니다.
select_all.sql
SELECT * FROM "kibana_sample_data_ecommerce"
결실
결과 얻기
{
"error" : {
"root_cause" : [
{
"type" : "ql_illegal_argument_exception",
"reason" : "Arrays (returned by [manufacturer]) are not supported"
}
],
"type" : "ql_illegal_argument_exception",
"reason" : "Arrays (returned by [manufacturer]) are not supported"
},
"status" : 500
}
오류Aray가 대응하지 않았다고 합니다.실제 데이터를 보기 위해 어떤 이유인지 translate API를 사용하여DSL로 변환해 봅니다.청원
GET /_sql/translate
{
"query": """
SELECT * FROM "kibana_sample_data_ecommerce"
"""
}
결실
{
"size": 1000,
"_source": {
"includes": [
"category",
"customer_first_name",
... 中略
"total_unique_products"
],
"excludes": []
},
"docvalue_fields": [
{
"field": "currency"
},
... 中略
{
"field": "user"
}
],
"sort": [
{
"_doc": {
"order": "asc"
}
}
]
}
실제 기반 인덱스검색의 요구를 제기해 보세요._검색 결과.json
{
"took" : 8,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 4675,
"relation" : "eq"
},
"max_score" : null,
"hits" : [
{
"_index" : "kibana_sample_data_ecommerce",
"_type" : "_doc",
"_id" : "uzf7j3YBp8s7-c5IvNTe",
"_score" : null,
"_source" : {
"customer_full_name" : "Eddie Underwood",
"customer_last_name" : "Underwood",
"customer_first_name" : "Eddie",
"day_of_week_i" : 0,
"total_quantity" : 2,
"taxless_total_price" : 36.98,
"total_unique_products" : 2,
"category" : [
"Men's Clothing"
],
"manufacturer" : [
"Elitelligence",
"Oceanavigations"
],
"products" : [
{
"tax_amount" : 0,
"taxful_price" : 11.99,
"quantity" : 1,
"taxless_price" : 11.99,
"discount_amount" : 0,
"base_unit_price" : 11.99,
"discount_percentage" : 0,
"product_name" : "Basic T-shirt - dark blue/white",
"manufacturer" : "Elitelligence",
"min_price" : 6.35,
"unit_discount_amount" : 0,
"price" : 11.99,
"product_id" : 6283,
"base_price" : 11.99,
"_id" : "sold_product_584677_6283",
"category" : "Men's Clothing"
},
{
"tax_amount" : 0,
"taxful_price" : 24.99,
"quantity" : 1,
"taxless_price" : 24.99,
"discount_amount" : 0,
"base_unit_price" : 24.99,
"discount_percentage" : 0,
"product_name" : "Sweatshirt - grey multicolor",
"manufacturer" : "Oceanavigations",
"min_price" : 11.75,
"unit_discount_amount" : 0,
"price" : 24.99,
"product_id" : 19400,
"base_price" : 24.99,
"_id" : "sold_product_584677_19400",
"category" : "Men's Clothing"
}
],
"taxful_total_price" : 36.98
},
"fields" : {
"products.sku" : [
"ZO0299602996",
"ZO0549605496"
],
"customer_phone" : [
""
],
"geoip.city_name" : [
"Cairo"
],
"geoip.region_name" : [
"Cairo Governorate"
],
"type" : [
"order"
],
"order_date" : [
"1609752528000"
],
"geoip.location" : [
"30.09999997448176, 31.29999996162951"
],
"geoip.country_iso_code" : [
"EG"
],
"products.created_on" : [
"1482744528000",
"1482744528000"
],
"currency" : [
"EUR"
],
"geoip.continent_name" : [
"Africa"
],
"customer_id" : [
"38"
],
"sku" : [
"ZO0299602996",
"ZO0549605496"
],
"order_id" : [
"584677"
],
"user" : [
"eddie"
],
"customer_gender" : [
"MALE"
],
"email" : [
"[email protected]"
],
"event.dataset" : [
"sample_ecommerce"
],
"day_of_week" : [
"Monday"
]
},
"sort" : [
0
]
}
]
}
}
결과를 보면 category
, manufacture
등 Aray 유형의 필드를 포함한다.이는 제약에 기재된 사항과 마찬가지로 앞으로 Aray형의 필드를 선택해서 피하지 말아야 한다.
order id 내림차순으로 Top10 고객 이름 얻기
query
SELECT customer_full_name FROM "kibana_sample_data_ecommerce" ORDER BY order_id DESC LIMIT 10
DSL{
"size" : 10,
"_source" : {
"includes" : [
"customer_full_name"
],
"excludes" : [ ]
},
"sort" : [
{
"order_id" : {
"order" : "desc",
"missing" : "_first",
"unmapped_type" : "keyword"
}
}
]
}
result{
"columns" : [
{
"name" : "customer_full_name",
"type" : "text"
}
],
"rows" : [
[
"Jim Pratt"
],
... 中略
[
"Wilhemina St. Graham"
]
]
}
customer_first_반복해서 가져오기name
query
SELECT DISTINCT customer_first_name from "kibana_sample_data_ecommerce"
result{
"error" : {
"root_cause" : [
{
"type" : "verification_exception",
"reason" : "Found 1 problem\nline 2:8: SELECT DISTINCT is not yet supported"
}
],
"type" : "verification_exception",
"reason" : "Found 1 problem\nline 2:8: SELECT DISTINCT is not yet supported"
},
"status" : 400
}
Limitation 페이지에는 표시되지 않지만 DISTINCT 문은 지원되지 않는 것 같습니다.Aggregation이 얻을 수 있는 내용이라 조금 아쉽다.taxless_total_price 100 이상 200 이하order id 10개 얻기
query
SELECT order_id
FROM kibana_sample_data_ecommerce
WHERE taxless_total_price BETWEEN 100 AND 200
LIMIT 10
DSL{
"size" : 10,
"query" : {
"range" : {
"taxless_total_price" : {
"from" : 100,
"to" : 200,
"include_lower" : true,
"include_upper" : true,
"time_zone" : "Z",
"boost" : 1.0
}
}
},
"_source" : false,
"stored_fields" : "_none_",
"docvalue_fields" : [
{
"field" : "order_id"
}
],
"sort" : [
{
"_doc" : {
"order" : "asc"
}
}
]
}
result{
"columns" : [
{
"name" : "order_id",
"type" : "keyword"
}
],
"rows" : [
[
"584058"
],
... 中略
[
"578650"
]
]
}
각 고객명의 주문서 수를 얻다
query
SELECT COUNT(customer_full_name), customer_full_name FROM kibana_sample_data_ecommerce GROUP BY customer_full_name
DSL{
"size" : 0,
"_source" : false,
"stored_fields" : "_none_",
"aggregations" : {
"groupby" : {
"composite" : {
"size" : 1000,
"sources" : [
{
"f8f23918" : {
"terms" : {
"field" : "customer_full_name.keyword",
"missing_bucket" : true,
"order" : "asc"
}
}
}
]
},
"aggregations" : {
"8df1ff4b" : {
"filter" : {
"exists" : {
"field" : "customer_full_name",
"boost" : 1.0
}
}
}
}
}
}
}
result{
"columns" : [
{
"name" : "COUNT(customer_full_name)",
"type" : "long"
},
{
"name" : "customer_full_name",
"type" : "text"
}
],
"rows" : [
[
2,
"Abd Adams"
],
... 中略
[
1,
"Abd Bradley"
]
]
}
JOIN
데이터 준비
JOIN 대상 테이블을 작성하려면 다음 정의를 사용하여 색인을 작성합니다.
PUT /ecommerce_customer_info
{
"mappings": {
"properties": {
"customer_id": {
"type": "integer",
"fields": {
"keyword": {
"type": "keyword"
}
}
},
"customer_full_name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
}
}
}
}
}
}
임시로 몇 개의 데이터를 투입한다.POST /_bulk
{"index": {"_index": "ecommerce_customer_info"}}
{"customer_id": 1, "customer_full_name": "Eddie Underwood"}
{"index": {"_index": "ecommerce_customer_info"}}
{"customer_id": 2, "customer_full_name": "Mary Bailey"}
{"index": {"_index": "ecommerce_customer_info"}}
{"customer_id": 3, "customer_full_name": "Gwen Butler"}
{"index": {"_index": "ecommerce_customer_info"}}
{"customer_id": 4, "customer_full_name": "Diane Chandler"}
질의 실행
query
SELECT e.customer_id
FROM kibana_sample_data_ecommerce k
INNER JOIN ecommerce_customer_info e
ON k.customer_full_name = e.customer_full_name
result{
"error" : {
"root_cause" : [
{
"type" : "parsing_exception",
"reason" : "line 4:2: Queries with JOIN are not yet supported"
}
],
"type" : "parsing_exception",
"reason" : "line 4:2: Queries with JOIN are not yet supported"
},
"status" : 400
}
JOIN 문은 DISTINCT 문과 마찬가지로 Limitations 페이지가 지원되지 않습니다.원래 Elasticsearch의 순기능을 사용하면 JOIN이 할 수 없기 때문에 지원하지 않으면 이해할 수 있다.
전체 텍스트 찾기
여기서 일반적인 SQL에서 벗어났지만 Elastic search처럼 전문 검색을 시도해 보세요.
Full-Text Search Functions를 보면 2010/12는 지금 이하로 지지를 받고 있다.
smith에 맞는 이름을 가진 고객의order id
query
SELECT order_id FROM kibana_sample_data_ecommerce WHERE MATCH(customer_full_name, 'smith')
DSL{
"size" : 1000,
"query" : {
"match" : {
"customer_full_name" : {
"query" : "smith",
"operator" : "OR",
"prefix_length" : 0,
"max_expansions" : 50,
"fuzzy_transpositions" : true,
"lenient" : false,
"zero_terms_query" : "NONE",
"auto_generate_synonyms_phrase_query" : true,
"boost" : 1.0
}
}
},
"_source" : false,
"stored_fields" : "_none_",
"docvalue_fields" : [
{
"field" : "order_id"
}
],
"sort" : [
{
"_doc" : {
"order" : "asc"
}
}
]
}
result{
"columns" : [
{
"name" : "order_id",
"type" : "keyword"
}
],
"rows" : [
[
"557262"
],
... 中略
[
"573691"
]
]
}
smith에 이름이 맞는 고객을 매칭도 순서대로 점수를 매기다
query
SELECT customer_full_name
FROM kibana_sample_data_ecommerce
WHERE MATCH(customer_full_name, 'smith')
ORDER BY SCORE()
DSL{
"size" : 1000,
"query" : {
"match" : {
"customer_full_name" : {
"query" : "smith",
"operator" : "OR",
"prefix_length" : 0,
"max_expansions" : 50,
"fuzzy_transpositions" : true,
"lenient" : false,
"zero_terms_query" : "NONE",
"auto_generate_synonyms_phrase_query" : true,
"boost" : 1.0
}
}
},
"_source" : {
"includes" : [
"customer_full_name"
],
"excludes" : [ ]
},
"sort" : [
{
"_score" : {
"order" : "asc"
}
}
]
}
result{
"columns" : [
{
"name" : "customer_full_name",
"type" : "text"
}
],
"rows" : [
[
"Wilhemina St. Smith"
],
... 中略
[
"Tariq Smith"
]
]
}
이름에 smith가 포함되어 있어 비슷한 결과를 얻었다.최후
이번 기고문에서는 Elasticsearch SQL을 사용하여 어느 정도의 작업을 수행할 수 있는지 검증했습니다.
개인적으로 SCORE 함수가 잘 준비되어 있어 전문 검색 솔루션의 특색을 좋아합니다.다른 한편, 지원하지 않는 조회도 많아 로그를 분석하고 데이터를 추출할 때 사용하기도 힘들다.
또 translate API를 사용함으로써 초보자의 학습을 지원한다는 인상을 남겼다.선교할 때 사용할 수 있을 것 같아요.
다만, 이쪽 SQL 기능과 비교하면 Open Distro for Elasticsearch SQL 할 수 있는 일이 많고, 큐리 워크벤치 등도 있어 부드러운 인상을 준다.
다양한 선택이 있었지만 본격적인 플러그인으로 앞으로 발전할 것으로 기대된다.
참고 자료
공식 문서
각주
https://github.com/elastic/elasticsearch/blob/master/licenses/ELASTIC-LICENSE.txt 각 요금 체계와 사용 가능한 기능은 여기.을 참조하십시오.↩︎
Reference
이 문제에 관하여(SQL 시작), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/pakio/articles/elasticsearch-sql텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)