1. 基本概念
1.1 index(索引)
在Elasticsearch中索引(index)类似mysql的表,代表文档数据的集合,文档指的是ES中存储的一条数据。
1.2 Document(文档)
Elasticsearch是面向文档的数据库,文档是最基本的存储单元,文档类似mysql表中的一行数据。简单的说在ES中,文档指的就是一条JSON数据。
1.3 Field(文档字段)
文档由多个json字段(Field)组成, 这里的字段类似mysql中表的字段。
1.4 mapping (映射)
Elasticsearch的mapping (映射)类似mysql中的表结构定义,每个索引都有一个映射规则,我们可以通过定义索引的映射规则,提前定义好文档的json结构和字段类型,如果没有定义索引的映射规则,Elasticsearch会在写入数据的时候,根据我们写入的数据字段推测出对应的字段类型,相当于自动定义索引的映射规则。
类比MYSQL存储结构:
元数据的字段名都是以下划线开头的
常见的元数据如下:
- _index - 代表当前JSON文档所属的文档名字
- _type - 代表当前JSON文档所属的类型,虽然新版ES废弃了type的用法,但是元数据还是可以看到
- _id - 文档唯一Id, 如果我们没有为文档指定id,系统会自动生成
- _source - 代表我们插入进去的JSON数据
- _version - 文档的版本号,每修改一次文档数据,字段就会加1,这个字段新版的ES已经不使用了
- _seq_no - 文档的版本号, 替代老的_version字段
- _primary_term - 文档所在主分区,这个可以跟_seq_no字段搭配实现乐观锁
开发实战:
第三方开发者维护的库 olivere/elastic
官方的Golang客户端 go-elasticsearch
olivere/elastic 使用
package main
import (
"context"
"fmt"
"github.com/olivere/elastic/v7"
"log"
"os"
"reflect"
"time"
)
// 查询结果定义
type QueryInfo struct {
Domain string `json:"domain"` // 查询域名
ClientIP string `json:"client_ip"` // 来源IP
Scheme string `json:"scheme"` // 协议类型
Referer string `json:"referer"` // 请求来源
Url string `json:"url"` // 请求url
HttpCode string `json:"http_code"` // 返回状态码
Method string `json:"method"` // 请求方法
}
// 初始化变量
var (
queryInfo QueryInfo
indexName = "chegva_ngx_proxy_log"
// es集群地址列表:https://sgp.api.es.che/product/es/cluster-list
apiAddresses = []string{"http://sgp.api.es.che"} // elasticsearch 服务地址,多个服务地址使用逗号分隔
username, password = "anzhihe", "anzhihe"
client *elastic.Client
res *elastic.SearchResult
err error
ctx context.Context
)
func init() {
// 连接es集群
client, err = elastic.NewClient(
elastic.SetURL(apiAddresses...),
elastic.SetBasicAuth(username, password),
// 允许您指定弹性是否应该定期检查集群(默认为真)
elastic.SetSniff(false),
// 设置监控检查时间间隔
elastic.SetHealthcheckInterval(10*time.Second),
// 设置错误日志输出
elastic.SetErrorLog(log.New(os.Stderr, "ELASTIC ", log.LstdFlags)),
// 设置info日志输出
elastic.SetInfoLog(log.New(os.Stdout, "", log.LstdFlags)))
if err != nil {
fmt.Println("连接失败:%v\n", err)
panic(err)
}
fmt.Println("连接成功", client)
}
// 查询日志
func Search() {
// 执行ES请求需要提供一个上下文对象
ctx = context.Background()
// 创建bool组合查询;must条件类似SQL的and;must_not与must作用相反;should类似SQL中的or,只要匹配区中一个就行
//boolQuery := elastic.NewBoolQuery().Must()
// 创建查询
// term精确查询;terms多值查询类似SQL的in查询
domainQuery := elastic.NewTermQuery("domain", "api.pay.chegva.com")
// Match查询,匹配单个字段
urlQuery := elastic.NewMatchQuery("url", "/pay/")
// Ranges范围查询
timeQuery := elastic.NewRangeQuery("timestamp").
Gte("2022-02-22").
Lte("now").
Format("yyyy-MM-dd")
// Filter 多重条件筛选
boolSearch := elastic.NewBoolQuery().
Filter(domainQuery).
Filter(urlQuery).
Filter(timeQuery)
// 设置bool查询的must条件, 组合了两个子查询
//boolQuery.Must(domainQuery, timeQuery)
res, err = client.Search().
Index(indexName).
Query(boolSearch).
From(0).Size(10). // 拿前10个结果,默认不能大于10000
Pretty(true).
Do(ctx) // 执行
if err != nil {
panic(err)
}
total := res.TotalHits()
fmt.Printf("Found %d results\n", total)
if total > 0 {
printQueryInfo(res, err)
} else {
fmt.Println("Not found!")
}
}
// 打印查询到的输出
func printQueryInfo(res *elastic.SearchResult, err error) {
if err != nil {
print(err.Error())
return
}
// 通过Each方法,将es结果的json结构转换成struct对象
for _, item := range res.Each(reflect.TypeOf(queryInfo)) { //从搜索结果中取数据的方法
if q, ok := item.(QueryInfo); ok {
fmt.Printf("%#v\n", q)
}
}
}
func main() {
Search()
}
官方库go-elasticsearch使用:
package main
import (
"bytes"
"encoding/json"
"fmt"
"github.com/elastic/go-elasticsearch/v7"
"log"
)
func main() {
cfg := elasticsearch.Config{
Addresses: []string{
"http://sgp.api.es.che",
},
Username: "anzhihe",
Password: "anzhihe",
}
var buf bytes.Buffer
query := map[string]interface{}{
"query": map[string]interface{}{
"match": map[string]interface{}{
"domain": "api.pay.chegva.com",
},
},
}
if err := json.NewEncoder(&buf).Encode(query); err != nil {
log.Fatalf("Error encoding query: %s", err)
}
es, _ := elasticsearch.NewClient(cfg)
log.Println(es.Info())
result, err := es.Search(es.Search.WithIndex("chegva_ngx_proxy_log"), es.Search.WithBody(&buf))
if err != nil {
fmt.Println(err)
}
fmt.Println(result)
}
除上述使用方案,还可以使用 Http请求接口:
func query(url string,username string,password string) {
jsonData := `{"query": {"term": {"request.data.id": "953c142cac566635120578a"}}}`
req, _ := http.NewRequest("POST", url, strings.NewReader(jsonData))
req.Header.Add("Content-Type", "application/json")
req.SetBasicAuth(username, password)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(string(body))
}
term多条件查询
{
"query": {
"bool": {
"filter": [
{
"match_phrase": {
"appid": "network"
}
},
{
"match_phrase": {
"requestid": "bbf60d576b6a08a8c3c1f2cd9"
}
}
]
}
}
}
参考文章:
https://blog.csdn.net/qq_3785...
https://www.tizi365.com/archi...
https://blog.csdn.net/leo_jk/...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。