wutiangan commented on a change in pull request #3867:
URL: https://github.com/apache/incubator-doris/pull/3867#discussion_r440109428



##########
File path: docs/zh-CN/extending-doris/doris-on-es.md
##########
@@ -30,72 +30,320 @@ Doris-On-ES将Doris的分布式查询规划能力和ES(Elasticsearch)的全文
  
  1. ES中的多index分布式Join查询
  2. Doris和ES中的表联合查询,更复杂的全文检索过滤
- 3. ES keyword类型字段的聚合查询:适用于index 频繁发生变化、单个分片文档数量千万级以上且该字段基数(cardinality)非常大
 
 本文档主要介绍该功能的实现原理、使用方式等。
 
 ## 名词解释
 
-* FE:Frontend,Doris 的前端节点。负责元数据管理和请求接入。
-* BE:Backend,Doris 的后端节点。负责查询执行和数据存储。
-* Elasticsearch(ES):目前最流行的开源分布式搜索引擎。
-* DataNode:ES的数据存储与计算节点。
-* MasterNode:ES的Master节点,管理元数据、节点、数据分布等。
-* scroll:ES内置的数据集游标特性,用来对数据进行流式扫描和过滤。
+### Doirs相关
+* FE:Frontend,Doris 的前端节点,负责元数据管理和请求接入
+* BE:Backend,Doris 的后端节点,负责查询执行和数据存储
 
+### ES相关
+* DataNode:ES的数据存储与计算节点
+* MasterNode:ES的Master节点,管理元数据、节点、数据分布等
+* scroll:ES内置的数据集游标特性,用来对数据进行流式扫描和过滤
+* _source: 导入时传入的原始JSON格式文档内容
+* doc_values: ES/Lucene 中字段的列式存储定义
+* keyword: 字符串类型字段,ES/Lucene不会对文本内容进行分词处理
+* text: 字符串类型字段,ES/Lucene会对文本内容进行分词处理,分词器需要用户指定,默认为standard英文分词器
 
-## 如何使用
 
-### 创建外表
+## 使用方法
+
+### 创建ES索引
 
 ```
-CREATE EXTERNAL TABLE `es_table` (
-  `id` bigint(20) COMMENT "",
+PUT test
+{
+   "settings": {
+      "index": {
+         "number_of_shards": "1",
+         "number_of_replicas": "0"
+      }
+   },
+   "mappings": {
+      "doc": { // ES 7.x版本之后创建索引时不需要指定type,会有一个默认且唯一的`_doc` type
+         "properties": {
+            "k1": {
+               "type": "long"
+            },
+            "k2": {
+               "type": "date"
+            },
+            "k3": {
+               "type": "keyword"
+            },
+            "k4": {
+               "type": "text",
+               "analyzer": "standard"
+            },
+            "k5": {
+               "type": "float"
+            }
+         }
+      }
+   }
+}
+```
+
+### ES索引导入数据
+
+```
+POST /_bulk
+{"index":{"_index":"test","_type":"doc"}}
+{ "k1" : 100, "k2": "2020-01-01", "k3": "Trying out Elasticsearch", "k4": 
"Trying out Elasticsearch", "k5": 10.0}
+{"index":{"_index":"test","_type":"doc"}}
+{ "k1" : 100, "k2": "2020-01-01", "k3": "Trying out Doris", "k4": "Trying out 
Doris", "k5": 10.0}
+{"index":{"_index":"test","_type":"doc"}}
+{ "k1" : 100, "k2": "2020-01-01", "k3": "Doris On ES", "k4": "Doris On ES", 
"k5": 10.0}
+{"index":{"_index":"test","_type":"doc"}}
+{ "k1" : 100, "k2": "2020-01-01", "k3": "Doris", "k4": "Doris", "k5": 10.0}
+{"index":{"_index":"test","_type":"doc"}}
+{ "k1" : 100, "k2": "2020-01-01", "k3": "ES", "k4": "ES", "k5": 10.0}
+```
+
+### Doris中创建ES外表
+
+```
+CREATE EXTERNAL TABLE `test` (
+  `k1` bigint(20) COMMENT "",
+  `k2` datetime COMMENT "",
+  `k3` varchar(20) COMMENT "",
+  `k4` varchar(100) COMMENT "",
+  `k5` float COMMENT ""
+) ENGINE=ELASTICSEARCH // ENGINE必须是Elasticsearch
+PROPERTIES (
+"hosts" = "http://192.168.0.1:8200,http://192.168.0.2:8200";,
+"index" = "test”,
+"type" = "doc",
+
+"user" = "root",
+"password" = "root"
+);
+```
+
+参数说明:
+
+参数 | 说明
+---|---
+**hosts** | ES集群地址,可以是一个或多个,也可以是ES前端的负载均衡地址
+**index** | 对应的ES的index名字
+**type** | index的type,不指定的情况会使用_doc
+**user** | ES集群用户名
+**password** | 对应用户的密码信息
+
+* ES 7.x之前的集群请注意在建表的时候选择正确的**索引类型type**
+* 认证方式仅支持Http Bastic认证,完全开源的ES集群用户和密码不需要指定,需要确保该用户有访问: 
/\_cluster/state/、\_nodes/http等路径权限和对index的读权限
+* Doris表中的列名需要和ES中的字段名完全匹配,字段类型应该保持一致
+*  **ENGINE**必须是 **Elasticsearch**
+
+##### 过滤条件下推
+`Doris On ES`一个重要的功能就是过滤条件的下推: 
过滤条件下推给ES,这样只有真正满足条件的数据才会被返回,能够显著的提高查询性能和降低Doris和Elasticsearch的CPU、memory、IO利用率
+
+下面的操作符(Operators)会被优化成如下ES Query:
+
+| SQL syntax  | ES 5.x+ syntax | 
+|-------|:---:|
+| =   | term query|
+| in  | terms query   |
+| > , < , >= , ⇐  | range query |
+| and  | bool.filter   |
+| or  | bool.should   |
+| not  | bool.must_not   |
+| not in  | bool.must_not + terms query |
+| is\_not\_null  | exists query |
+| is\_null  | bool.must_not + exists query |
+| esquery  | ES原生json形式的QueryDSL   |
+
+##### 数据类型映射
+
+Doris\ES  |  byte | short | integer | long | float | double| keyword | text | 
date
+------------- | ------------- | ------  | ---- | ----- | ----  | ------ | 
----| --- | --- |
+tinyint  | &radic; |  |  |  |   |   |   |   |  
+smallint | &radic; | &radic; |  | |   |   |   |   |  
+int | &radic; |  &radic; | &radic; | |   |   |   |   |  
+bigint | &radic;  | &radic;  | &radic;  | &radic; |   |   |   |   | 
+float |   |   |   |   | &radic; |   |   |   |  
+double |   |   |   |   |   | &radic; |   |   |  
+char |   |   |   |   |   |   | &radic; | &radic; |  
+varchar |  |   |   |   |   |   | &radic; | &radic; |   
+date |   |   |   |   |   |   |   |   | &radic;|  
+datetime |   |   |   |   |   |   |   |   | &radic;|  
+
+
+### 启用列式扫描优化查询速度(enable\_docvalue\_scan=true)
+
+```
+CREATE EXTERNAL TABLE `test` (
   `k1` bigint(20) COMMENT "",
   `k2` datetime COMMENT "",
   `k3` varchar(20) COMMENT "",
   `k4` varchar(100) COMMENT "",
   `k5` float COMMENT ""
 ) ENGINE=ELASTICSEARCH
-PARTITION BY RANGE(`id`)
-()
 PROPERTIES (
 "hosts" = "http://192.168.0.1:8200,http://192.168.0.2:8200";,
+"index" = "test”,
+"type" = "doc",
 "user" = "root",
 "password" = "root",
-"index" = "tindex”,
-"type" = "doc"
+
+"enable_docvalue_scan" = "true"
 );
 ```
 
 参数说明:
 
 参数 | 说明
 ---|---
-hosts | ES集群连接地址,可指定一个或多个,Doris通过这个地址获取到ES版本号、index的shard分布信息
-user | 开启basic认证的ES集群的用户名,需要确保该用户有访问: 
/\_cluster/state/\_nodes/http等路径权限和对index的读权限
-password | 对应用户的密码信息
-index | Doris中的表对应的ES的index名字,可以是alias
-type | 指定index的type,默认是_doc
-transport | 内部保留,默认为http
+**enable\_docvalue\_scan** | 是否开启通过ES/Lucene列式存储获取查询字段的值,默认为false
+
+开启后Doris从ES中获取数据会遵循以下两个原则:
+
+* **尽力而为**: 自动探测要读取的字段是否开启列式存储(doc_value: 
true),如果获取的字段全部有列存,Doris会从列式存储中获取所有字段的值
+* **自动降级**: 如果要获取的字段只要有一个字段没有列存,所有字段的值都会从行存`_source`中解析获取
+
+##### 优势:
+
+默认情况下,Doris On 
ES会从行存也就是`_source`中获取所需的所有列,`_source`的存储采用的行式+json的形式存储,在批量读取性能上要劣于列式存储,尤其在只需要少数列的情况下尤为明显,只获取少数列的情况下,docvalue的性能大约是_source性能的十几倍
+
+##### 注意
+1. `text`类型的字段在ES中是没有列式存储,因此如果要获取的字段值有`text`类型字段会自动降级为从`_source`中获取
+2. 在获取的字段数量过多的情况下(`>= 25`),从`docvalue`中获取字段值的性能会和从`_source`中获取字段值基本一样
 
-### 查询
 
-#### 基本条件过滤
+### 探测keyword类型字段(enable\_keyword\_sniff=true)
+
+```
+CREATE EXTERNAL TABLE `test` (
+  `k1` bigint(20) COMMENT "",
+  `k2` datetime COMMENT "",
+  `k3` varchar(20) COMMENT "",
+  `k4` varchar(100) COMMENT "",
+  `k5` float COMMENT ""
+) ENGINE=ELASTICSEARCH
+PROPERTIES (
+"hosts" = "http://192.168.0.1:8200,http://192.168.0.2:8200";,
+"index" = "test”,
+"type" = "doc",
+"user" = "root",
+"password" = "root",
+
+"enable_keyword_sniff" = "true"
+);
+```
+
+参数说明:
+
+参数 | 说明
+---|---
+**enable\_keyword\_sniff** | 是否对ES中字符串类型分词类型(**text**) `fields` 
进行探测,获取额外的未分词(**keyword**)字段名(multi-fields机制)
+
+在ES中可以不建立index直接进行数据导入,这时候ES会自动创建一个新的索引,针对字符串类型的字段ES会创建一个既有`text`类型的字段又有`keyword`类型的字段,这就是ES的multi
 fields特性,mapping如下:
+
+```
+"k4": {
+   "type": "text",
+   "fields": {
+      "keyword": {   
+         "type": "keyword",
+         "ignore_above": 256
+      }
+   }
+}
+```
+对k4进行条件过滤时比如=,Doris On ES会将查询转换为ES的TermQuery
+
+SQL过滤条件:
+
+```
+k4 = "Doris On ES"
+```
+
+转换成ES的query DSL为:
+
+```
+"term" : {
+    "k4": "Doris On ES"
+
+}
+```
+
+因为k4的第一字段类型为`text`,在数据导入的时候就会根据k4设置的分词器(如果没有设置,就是standard分词器)进行分词处理得到doris、on、es三个Term,如下ES
 analyze API分析:
+
+```
+POST /_analyze
+{
+  "analyzer": "standard",
+  "text": "Doris On ES"
+}
+```
+分词的结果是:
+
+```
+{
+   "tokens": [
+      {
+         "token": "doris",
+         "start_offset": 0,
+         "end_offset": 5,
+         "type": "<ALPHANUM>",
+         "position": 0
+      },
+      {
+         "token": "on",
+         "start_offset": 6,
+         "end_offset": 8,
+         "type": "<ALPHANUM>",
+         "position": 1
+      },
+      {
+         "token": "es",
+         "start_offset": 9,
+         "end_offset": 11,
+         "type": "<ALPHANUM>",
+         "position": 2
+      }
+   ]
+}
+```
+查询时使用的是:
+
+```
+"term" : {
+    "k4": "Doris On ES"
+}
+```
+`Doris On ES`这个term匹配不到词典中的任何term,不会返回任何结果,而启用`enable_keyword_sniff: 
true`会自动将`k4 = "Doris On ES"`转换成`k4.keyword = "Doris On ES"`来完全匹配SQL语义,转换后的ES 
query DSL为:
+
+```
+"term" : {
+    "k4.keyword": "Doris On ES"
+}
+```
+
+`k4.keyword` 的类型是`keyword`,数据写入ES中是一个完整的term,所以可以匹配
+
+### 查询用法
+
+完成在Doris中建立ES外表后,除了无法使用Doris中的数据模型(rollup、预聚合、物化视图等)外并无区别
+
+#### 基本查询
 
 ```
 select * from es_table where k1 > 1000 and k3 ='term' or k4 like 'fu*z_'
 ```
 
-#### 扩展的esquery sql语法
+#### 扩展的esquery
 通过`esquery`函数将一些无法用sql表述的ES 
query如match、geoshape等下推给ES进行过滤处理,`esquery`的第一个列名参数用于关联`index`,第二个参数是ES的基本`Query 
DSL`的json表述,使用花括号`{}`包含,json的`root key`有且只能有一个,如match、geo_shape、bool等

Review comment:
       query后面需要加个括号,将如match、geoshape括起来




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org
For additional commands, e-mail: commits-h...@doris.apache.org

Reply via email to