SQL和Elasticsearch查询的对比
我大致总结了有关SQL和Elasticsearch查询的常见用法,各自是如何对应的。
环境
Elasticsearch的版本从6.2.4 升级到了7.5。
前提条件 (Qian ti tiao jian)
以下的条件为记载内容的前提。
在Elasticsearch中,可以省略URL的指定进行搜索。
在Elasticsearch中,当执行搜索时,会向以下URL发送请求。
{Elasticsearch的URL}/{索引名称}/_search
例如,对于名为product的表在SQL中进行索引,Elasticsearch会发送请求到以下URL。
http://localhost:9200/product/_search
假设以前述的URL进行请求,无需详细说明Elasticsearch请求的目标URL。
所有文字字符的数据类型都是关键字(不使用全文搜索)。
Elasticsearch具有全文搜索功能,字符串数据是否可进行全文搜索取决于字段的数据类型。
-
- 通常の文字列 : Keyword
全文検索対象 : Text
尽管关系数据库管理系统(RDBMS)也可以进行全文搜索,但不同的RDBMS处理方式有较大差异,所以在执行全文搜索时,我认为了解Elasticsearch专用的语法作为搜索方法比与SQL进行比较更好。
因此,在这种情况下,我们假设所有的字符串数据都是关键字(Keyword)数据类型的。
只需输入无限制地搜索。
在SQL中,没有WHERE子句的搜索,在Elasticsearch中可以使用Match All Query进行。
SELECT *
FROM product
{
"query": {
"match_all": {}
}
}
Elasticsearch的搜索结果会被存储在一个名为“hits”的字段中并返回。
指定获取数量和获取起始位置
在SQL中使用LIMIT(或者OFFSET或者ROWNUM)来指定获取的数量和起始位置,在Elasticsearch中可以使用From / Size来实现。
由于Elasticsearch使用了from和size两个参数,因此给出了一个示例来指定LIMIT和OFFSET。(请根据需要对应地调整为RDBMS)
例如,要跳过前5个并且只获取10个记录,可以按以下方式进行。
SELECT *
FROM product
LIMIT 10 OFFSET 5
{
"from": 5,
"size": 10,
"query": {
"match_all": {}
}
}
Elasticsearch的默认配置是”from”: 0, “size”: 10。
指定所需的列
在SQL中,要指定SELECT语句中的提取列,在Elasticsearch中使用Source过滤功能来实现。
SELECT
product_name,
product_count
FROM product
{
"_source": [
"product_name",
"product_count"
],
"query": {
"match_all": {}
}
}
刪除重複行
在SQL中使用SELECT语句时,通过指定DISTINCT关键字来删除重复行,在Elasticsearch中可以使用Field Collapsing功能。
SELECT DISTINCT
product_name
FROM product
{
"collapse": {
"field": "product_name"
},
"query": {
"match_all": {}
}
}
在数据库中搜索符合条件的数据(使用WHERE子句)。
在后面的例子中,我们提到了特定数据类型的情况,但是如果要指定其他数据类型,基本上也是类似的。
等於指定的數值
在SQL中,查找与特定值相等的数据可以使用Elasticsearch的Term Query进行搜索。
SELECT *
FROM product
WHERE product_name = 'りんご'
{
"query": {
"term": {
"product_name": {
"value": "りんご"
}
}
}
}
与指定的多个值之一相等(IN句)
在SQL中使用IN子句进行检索,在Elasticsearch中使用Terms Query进行检索。
SELECT *
FROM product
WHERE product_name IN ('りんご', 'にんじん')
{
"query": {
"terms": {
"product_name": [
"りんご",
"にんじん"
]
}
}
}
包含指定的值(LIKE语句)
在SQL中,使用LIKE句进行搜索,在Elasticsearch中可以使用通配符查询(Wildcard Query)。
SELECT *
FROM product
WHERE product_name LIKE '%じ%'
{
"query": {
"wildcard": {
"product_name": {
"value": "*じ*"
}
}
}
}
比指定的值大(或小)。
在SQL中,基于指定值的大小条件搜索,在Elasticsearch中使用Range Query。大小条件可按以下方式指定。
SELECT *
FROM product
WHERE product_count >= 10
{
"query": {
"range": {
"product_count": {
"gte" : 10
}
}
}
}
多个条件符合
在SQL中,指定多个条件进行搜索在Elasticsearch中使用Bool Query的must和should。多个条件可以如下指定。
如果是AND条件的情况下(如果是AND条件的情况下)
SELECT *
FROM product
WHERE product_name = 'りんご'
AND product_count >= 10
{
"query": {
"bool": {
"must": [
{
"term": {
"product_name": "りんご"
}
},
{
"range": {
"product_count": {
"gte": 10
}
}
}
]
}
}
}
如果是OR条件的情况
SELECT *
FROM product
WHERE product_name= 'りんご'
OR product_count >= 10
{
"query": {
"bool": {
"should": [
{
"term": {
"product_name": "りんご"
}
},
{
"range": {
"product_count": {
"gte": 10
}
}
}
]
}
}
}
在AND和OR的组合情况下
通过在 Bool Query 中嵌套 Bool Query,可以实现 AND 和 OR 的组合。
SELECT *
FROM product
WHERE product_count >= 10
AND (product_name = 'りんご' OR product_price = 100)
{
"query": {
"bool": {
"must": [
{
"range": {
"count": {
"gte": 10
}
}
},
{
"bool": {
"should": [
{
"term": {
"product_name": "りんご"
}
},
{
"term": {
"product_price": 100
}
}
]
}
}
]
}
}
}
在中文中进行更多的句子重述以获得相同的搜索结果,可以通过使用minimum_should_match参数来实现。然而,与SQL相比,我认为前面提到的方法更易理解。
不符合指定条件
在SQL中,如果不符合指定条件的搜索,则在Elasticsearch中使用Bool Query的must_not进行搜索。
SELECT *
FROM product
WHERE product_name <> 'りんご'
{
"query": {
"bool": {
"must_not": [
{
"term": {
"product_name": "りんご"
}
}
]
}
}
}
对获取的数据进行排序(使用ORDER BY子句)
在SQL中使用ORDER BY子句进行排序,而在Elasticsearch中则使用Sort功能进行排序。
SELECT *
FROM product
ORDER BY product_name ASC
{
"query": {
"match_all": {}
},
"sort": [
{
"product_name": {
"order": "asc"
}
}
]
}
对数据进行汇总
在Elasticsearch中,我们使用Aggregations进行数据聚合。与搜索相比,Elasticsearch有一些特殊的语法,可能会有些难以理解,但基本的语法如下所示。
{
"aggs": {
"{Aggregation名(わかりやすければ何でもOK)}": {
"{Aggregationの種類}": {}
}
}
Elasticsearch的聚合结果会存储在aggregations字段中返回,而不是hits字段。
搜索结果通常会一起存储在hits字段中返回,如果不需要搜索结果的话,可以将size设为0来指定。
计算指定列的平均值与最大值(汇总函数)。
在SQL中,使用聚合函数进行数据聚合,在Elasticsearch中使用Metrics Aggregations实现。
以下是SQL的聚合函数与Elasticsearch的对应列表。
SELECT
AVG(product_count)
FROM product
{
"aggs": {
"product_count_avg": {
"avg": {
"field": "product_count"
}
}
}
}
按照具有相同数值的数据进行汇总(使用GROUP BY子句)。
在Elasticsearch中,使用Terms Aggregation来执行类似于SQL中的GROUP BY语句的数据汇总。
SELECT
product_name
FROM product
GROUP BY product_name
{
"aggs": {
"product_name_aggs": {
"terms": {
"field": "product_name",
"size": 10
}
}
}
}
使用术语聚合计算的结果将被汇总到指定的前N个条目中(例如,10个)。
如果想与聚合函数结合使用,需要将Aggregation嵌套起来。
SELECT
AVG(product_count)
FROM product
GROUP BY product_name
{
"aggs": {
"product_name_aggs": {
"terms": {
"field": "product_name",
"size": 10
},
"aggs": {
"product_count_avg": {
"avg": {
"field": "product_count"
}
}
}
}
}
}
根据指定条件进行数据汇总(与WHERE子句结合使用)
如果你想筛选出特定的原始数据并进行汇总,你可以通过与查询语句(query)结合来实现。
SELECT
AVG(product_count)
FROM product
WHERE product_name = 'りんご'
{
"size": 0,
"query": {
"term": {
"product_name": {
"value": "りんご"
}
}
},
"aggs": {
"product_count_avg": {
"avg": {
"field": "product_count"
}
}
}
}
有点难理解, 但是通过查询筛选的结果将被返回到hits中, 而汇总结果将被返回到aggregations中, 它们是两个不同的项目。
如果只需要获取汇总结果, 可以通过像上面的示例一样在size中指定0, 这样将不会有任何返回到hits中, 从而减轻了响应数据的负担。
(aggregations将会返回根据查询条件匹配的数据进行汇总的结果)
对于集计结果进行条件指定(使用HAVING子句)。
在Elasticsearch中,使用Bucket Selector聚合进行检索对应于SQL中使用HAVING子句对聚合结果的查询。
SELECT
product_name,
SUM(product_count)
FROM product
GROUP BY product_name
HAVING SUM(product_count) > 10
{
"aggs": {
"product_name_aggs": {
"terms": {
"field": "product_name",
"size": 10
},
"aggs": {
"product_count_sum": {
"sum": {
"field": "product_count"
}
},
"product_count_sum_bucket": {
"bucket_selector": {
"buckets_path": {
"count_sum": "product_count_sum"
},
"script": "params.count_sum > 10"
}
}
}
}
}
}
在buckets_path中指定要进行筛选条件的字段。
例子中,我们将product_count_sum作为等价于SUM(product_count)的条件指定对象。
在脚本中,您可以写入筛选条件。
如果您想要使用在buckets_path中指定的值,可以通过指定变量名为params.count_sum来实现。
params是用于引用执行查询中的变量的指定值。
其他的例子包括JOIN和子查询。
由于Elasticsearch不是关系型数据库,所以很遗憾地没有像JOIN和子查询一样的功能。
为了能够成功搜索,您需要将数据通过非规范化或使用Nested数据类型来嵌套数据进行注册。