golang将SQL转换为Elasticsearch DSL查询语句插件库elasticsql的使用

Golang将SQL转换为Elasticsearch DSL查询语句插件库elasticsql的使用

概述

elasticsql是一个将SQL转换为Elasticsearch DSL查询语句的Golang工具库。

功能支持

  • SQL和表达式
  • SQL或表达式
  • 等于(=)支持
  • 不等于(!=)支持
  • 大于(>)支持
  • 大于等于(>=)支持
  • 小于(<)支持
  • 小于等于(<=)支持
  • SQL IN表达式(如id in (1,2,3))
  • SQL NOT IN表达式(如id not in (1,2,3))
  • 括号布尔支持(如where (a=1 or b=1) and (c=1 or d=1))
  • SQL LIKE表达式(当前使用match phrase,未来可能改为wildcard)
  • SQL ORDER BY支持
  • SQL LIMIT支持
  • SQL NOT LIKE表达式
  • 字段缺失检查
  • 支持聚合函数如count(*), count(field), min(field), max(field), avg(field)
  • 支持非标准SQL聚合函数如stats(field), extended_stats(field), percentiles(field)

使用方法

安装:

go get -u github.com/cch123/elasticsql

示例代码:

package main

import (
    "fmt"
    "github.com/cch123/elasticsql"
)

var sql = `
select * from aaa
where a=1 and x = '三个男人'
and create_time between '2015-01-01T00:00:00+0800' and '2016-01-01T00:00:00+0800'
and process_id > 1 order by id desc limit 100,10
`

func main() {
    dsl, esType, _ := elasticsql.Convert(sql)
    fmt.Println(dsl)
    fmt.Println(esType)
}

输出结果:

{
    "query": {
        "bool": {
            "must": [
                {
                    "match": {
                        "a": {
                            "query": "1",
                            "type": "phrase"
                        }
                    }
                },
                {
                    "match": {
                        "x": {
                            "query": "三个男人",
                            "type": "phrase"
                        }
                    }
                },
                {
                    "range": {
                        "create_time": {
                            "from": "2015-01-01T00:00:00+0800",
                            "to": "2016-01-01T00:00:00+0800"
                        }
                    }
                },
                {
                    "range": {
                        "process_id": {
                            "gt": "1"
                        }
                    }
                }
            ]
        }
    },
    "from": 100,
    "size": 10,
    "sort": [
        {
            "id": "desc"
        }
    ]
}

aaa

注意事项

  1. 如果SQL中包含关键字(如order、timestamp等),需要使用反引号转义:
select * from `order` where `timestamp` = 1 and `desc`.id > 0
  1. 使用此工具需要了解Elasticsearch的term查询和match phrase查询的区别。

  2. 字段设置为analyzed或not analyzed会得到不同的结果。

其他信息

该工具尽量避免使用已弃用的DSL过滤器和聚合,因此与大多数Elasticsearch版本兼容。

如果有任何建议或想法,欢迎提交issue或Pull Request!

许可证

MIT


更多关于golang将SQL转换为Elasticsearch DSL查询语句插件库elasticsql的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang将SQL转换为Elasticsearch DSL查询语句插件库elasticsql的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用 elasticsql 将 SQL 转换为 Elasticsearch DSL

elasticsql 是一个 Go 语言库,可以将 SQL 查询语句转换为 Elasticsearch 的 DSL (Domain Specific Language) 查询语句。这对于熟悉 SQL 但需要与 Elasticsearch 交互的开发者来说非常有用。

安装 elasticsql

首先,使用 go get 安装 elasticsql:

go get github.com/cch123/elasticsql

基本使用方法

下面是一个简单的示例,展示如何将 SQL 转换为 Elasticsearch DSL:

package main

import (
	"fmt"
	"github.com/cch123/elasticsql"
)

func main() {
	sql := "select * from my_index where age > 20 and name = 'john' limit 10"
	
	dsl, _, err := elasticsql.Convert(sql)
	if err != nil {
		fmt.Println("转换失败:", err)
		return
	}
	
	fmt.Println("生成的DSL:")
	fmt.Println(dsl)
}

输出结果类似于:

{
  "query": {
    "bool": {
      "must": [
        {
          "range": {
            "age": {
              "gt": 20
            }
          }
        },
        {
          "term": {
            "name": "john"
          }
        }
      ]
    }
  },
  "size": 10
}

支持的功能

elasticsql 支持以下 SQL 特性:

  1. 基本查询:SELECT, FROM, WHERE
  2. 条件表达式:=, !=, >, >=, <, <=, AND, OR, NOT, IN, LIKE
  3. 聚合函数:COUNT, SUM, AVG, MAX, MIN
  4. 分组:GROUP BY
  5. 排序:ORDER BY
  6. 分页:LIMIT

更多示例

带聚合的查询

sql := "select count(*) as cnt, avg(age) as avg_age, max(age) as max_age from my_index where age > 20 group by gender"
dsl, _, err := elasticsql.Convert(sql)

带排序和分页的查询

sql := "select * from my_index where age > 20 order by age desc, name asc limit 10, 20"
dsl, _, err := elasticsql.Convert(sql)

带 IN 和 LIKE 的查询

sql := "select * from my_index where name in ('john', 'mike') and address like '%new york%'"
dsl, _, err := elasticsql.Convert(sql)

高级用法

指定索引类型

sql := "select * from my_index where age > 20"
dsl, table, err := elasticsql.ConvertWithTable(sql)
fmt.Println("索引名称:", table)

自定义转换选项

options := &elasticsql.ConvertOptions{
    DefaultField: "_all",  // 默认搜索字段
    DefaultLimit: 100,     // 默认限制
}

sql := "select * from my_index where query = 'test'"
dsl, _, err := elasticsql.ConvertWithOption(sql, options)

注意事项

  1. elasticsql 并不支持所有 SQL 语法,特别是复杂的 JOIN 操作
  2. 某些 Elasticsearch 特有的功能(如嵌套查询、地理位置查询)需要通过原生 DSL 实现
  3. 转换后的 DSL 可能需要根据实际需求进行微调
  4. 字段名中的特殊字符可能需要额外处理

完整示例

下面是一个完整的示例,展示如何将 SQL 转换为 DSL 并执行 Elasticsearch 查询:

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"

	"github.com/cch123/elasticsql"
	"github.com/olivere/elastic/v7"
)

func main() {
	// 1. 转换SQL为DSL
	sql := `select user, message from twitter 
           where retweets > 10 and user = 'kimchy' 
           order by retweets desc 
           limit 5`
	
	dsl, table, err := elasticsql.Convert(sql)
	if err != nil {
		log.Fatal("转换失败:", err)
	}
	
	fmt.Println("索引:", table)
	fmt.Println("生成的DSL:")
	fmt.Println(dsl)
	
	// 2. 连接到Elasticsearch
	client, err := elastic.NewClient(elastic.SetURL("http://localhost:9200"))
	if err != nil {
		log.Fatal("连接Elasticsearch失败:", err)
	}
	
	// 3. 执行查询
	var mapResp map[string]interface{}
	err = json.Unmarshal([]byte(dsl), &mapResp)
	if err != nil {
		log.Fatal("解析DSL失败:", err)
	}
	
	searchResult, err := client.Search().
		Index(table).
		Source(mapResp).
		Do(context.Background())
	
	if err != nil {
		log.Fatal("查询失败:", err)
	}
	
	// 4. 处理结果
	fmt.Printf("查询到 %d 条结果\n", searchResult.TotalHits())
	for _, hit := range searchResult.Hits.Hits {
		var item map[string]interface{}
		err := json.Unmarshal(hit.Source, &item)
		if err != nil {
			log.Printf("解析结果失败: %v", err)
			continue
		}
		fmt.Printf("ID: %s, 数据: %v\n", hit.Id, item)
	}
}

总结

elasticsql 是一个实用的工具,可以简化从 SQL 到 Elasticsearch DSL 的转换过程。虽然它不能覆盖所有 Elasticsearch 的高级查询功能,但对于大多数基本查询场景已经足够。对于更复杂的需求,你可能需要直接使用 Elasticsearch 的 DSL 或结合两者使用。

在实际项目中,建议先使用 elasticsql 进行快速原型开发,然后根据需要手动调整生成的 DSL 以获得最佳性能和功能。

回到顶部