Add Search() function, README and fix some lint errors

This commit changes the internal `search()` function into an exposed
`Search()` function that can be used to execute queries against an
instance of an ElasticSearch client. The per-query-type methods of
`Run()` are removed for now to prevent having to create them for every
type. `Search()` is agnostic.

A README.md file is added with some information, and a few lingering
lint errors are fixed.
This commit is contained in:
Ido Perlmuter 2020-02-18 18:43:19 +02:00
parent 6c8e71c188
commit 55000abc77
7 changed files with 109 additions and 16 deletions

View File

@ -1,3 +1,5 @@
run:
tests: false
linters: linters:
disable-all: true disable-all: true
enable: enable:

90
README.md Normal file
View File

@ -0,0 +1,90 @@
# esquery
`esquery` is an idiomatic, easy-to-use query builder for the [official Go client](https://github.com/elastic/go-elasticsearch) for [ElasticSearch](https://www.elastic.co/products/elasticsearch). It alleviates the need to use extremely nested maps of empty interfaces and serializing queries to JSON manually. It also helps eliminating common mistakes such as misspelling query types, as everything is statically typed.
## Usage
`esquery` can be used directly to build queries, with no need for external dependencies. It can execute the queries against an existing instance of `*esapi.API`, but the queries can also be manually converted to JSON if necessary.
```go
package main
import (
"context"
"log"
"bitbucket.org/scalock/esquery"
"github.com/elastic/go-elasticsearch/v7"
)
func main() {
es, err := elasticsearch.NewDefaultClient()
if err != nil {
log.Fatalf("Failed creating client: %s", err)
}
res, err := esquery.Search(
es,
esquery.
Bool().
Must(esquery.Term("title", "Go and Stuff")).
Filter(esquery.Term("tag", "tech")),
es.Search.WithContext(context.TODO()),
es.Search.WithIndex("test"),
)
if err != nil {
log.Fatalf("Failed searching for stuff: %s", err)
}
defer res.Body.Close()
// ...
}
```
## Notes
* Library currently supports v7 of the ElasticSearch Go client.
* The library cannot currently generate "short queries". For example, whereas
ElasticSearch can accept this:
```json
{ "query": { "term": { "user": "Kimchy" } } }
```
The library will always generate this:
```json
{ "query": { "term": { "user": { "value": "Kimchy" } } } }
```
This is also true for queries such as "bool", where fields like "must" can
either receive one query object, or an array of query objects. `esquery` will
generate an array even if there's only one query object.
## Supported queries
The following queries are currently supported:
| Query | `esquery` Function |
| ------------------------|---------------------- |
| `"match"` | `Match()` |
| `"match_bool_prefix"` | `MatchBoolPrefix()` |
| `"match_phrase"` | `MatchPhrase()` |
| `"match_phrase_prefix"` | `MatchPhrasePrefix()` |
| `"match_all"` | `MatchAll()` |
| `"match_none"` | `MatchNone()` |
| `"exists"` | `Exists()` |
| `"fuzzy"` | `Fuzzy()` |
| `"ids"` | `IDs()` |
| `"prefix"` | `Prefix()` |
| `"range"` | `Range()` |
| `"regexp"` | `Regexp()` |
| `"term"` | `Term()` |
| `"terms"` | `Terms()` |
| `"terms_set"` | `TermsSet()` |
| `"wildcard"` | `Wildcard()` |
| `"bool"` | `Bool()` |
| `"boosting"` | `Boosting()` |
| `"constant_score"` | `ConstantScore()` |
| `"dis_max"` | `DisMax()` |

9
es.go
View File

@ -5,7 +5,8 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/elastic/go-elasticsearch/esapi" "github.com/elastic/go-elasticsearch/v7"
"github.com/elastic/go-elasticsearch/v7/esapi"
) )
type ESQuery struct { type ESQuery struct {
@ -22,7 +23,11 @@ func encode(q json.Marshaler, b *bytes.Buffer) (err error) {
return nil return nil
} }
func search(q json.Marshaler, api *esapi.API, o ...func(*esapi.SearchRequest)) (res *esapi.Response, err error) { func Search(
api *elasticsearch.Client,
q json.Marshaler,
o ...func(*esapi.SearchRequest),
) (res *esapi.Response, err error) {
var b bytes.Buffer var b bytes.Buffer
err = encode(ESQuery{q}, &b) err = encode(ESQuery{q}, &b)
if err != nil { if err != nil {

6
go.mod
View File

@ -2,4 +2,8 @@ module bitbucket.org/scalock/esquery
go 1.13 go 1.13
require github.com/elastic/go-elasticsearch v0.0.0 require (
github.com/elastic/go-elasticsearch v0.0.0
github.com/elastic/go-elasticsearch/v7 v7.6.0
github.com/elastic/go-elasticsearch/v8 v8.0.0-20200210103600-aff00e5adfde
)

4
go.sum
View File

@ -1,2 +1,6 @@
github.com/elastic/go-elasticsearch v0.0.0 h1:Pd5fqOuBxKxv83b0+xOAJDAkziWYwFinWnBO0y+TZaA= github.com/elastic/go-elasticsearch v0.0.0 h1:Pd5fqOuBxKxv83b0+xOAJDAkziWYwFinWnBO0y+TZaA=
github.com/elastic/go-elasticsearch v0.0.0/go.mod h1:TkBSJBuTyFdBnrNqoPc54FN0vKf5c04IdM4zuStJ7xg= github.com/elastic/go-elasticsearch v0.0.0/go.mod h1:TkBSJBuTyFdBnrNqoPc54FN0vKf5c04IdM4zuStJ7xg=
github.com/elastic/go-elasticsearch/v7 v7.6.0 h1:sYpGLpEFHgLUKLsZUBfuaVI9QgHjS3JdH9fX4/z8QI8=
github.com/elastic/go-elasticsearch/v7 v7.6.0/go.mod h1:OJ4wdbtDNk5g503kvlHLyErCgQwwzmDtaFC4XyOxXA4=
github.com/elastic/go-elasticsearch/v8 v8.0.0-20200210103600-aff00e5adfde h1:Y9SZx8RQqFycLxi5W5eFmxMqnmijULVc3LMjBTtZQdM=
github.com/elastic/go-elasticsearch/v8 v8.0.0-20200210103600-aff00e5adfde/go.mod h1:xe9a/L2aeOgFKKgrO3ibQTnMdpAeL0GC+5/HpGScSa4=

View File

@ -5,8 +5,6 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"io" "io"
"github.com/elastic/go-elasticsearch/esapi"
) )
/******************************************************************************* /*******************************************************************************
@ -51,10 +49,6 @@ func (a MatchQuery) MarshalJSON() ([]byte, error) {
}) })
} }
func (a *MatchQuery) Run(api *esapi.API, o ...func(*esapi.SearchRequest)) (res *esapi.Response, err error) {
return search(*a, api, o...)
}
type matchParams struct { type matchParams struct {
Qry interface{} `json:"query"` Qry interface{} `json:"query"`
Anl string `json:"analyzer,omitempty"` Anl string `json:"analyzer,omitempty"`
@ -89,7 +83,7 @@ func MatchPhrasePrefix(fieldName string, simpleQuery ...interface{}) *MatchQuery
func newMatch(mType matchType, fieldName string, simpleQuery ...interface{}) *MatchQuery { func newMatch(mType matchType, fieldName string, simpleQuery ...interface{}) *MatchQuery {
var qry interface{} var qry interface{}
if simpleQuery != nil && len(simpleQuery) > 0 { if len(simpleQuery) > 0 {
qry = simpleQuery[len(simpleQuery)-1] qry = simpleQuery[len(simpleQuery)-1]
} }

View File

@ -2,8 +2,6 @@ package esquery
import ( import (
"encoding/json" "encoding/json"
"github.com/elastic/go-elasticsearch/esapi"
) )
// https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-all-query.html // https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-all-query.html
@ -28,10 +26,6 @@ func (a MatchAllQuery) MarshalJSON() ([]byte, error) {
return json.Marshal(map[string]matchAllParams{mType: a.params}) return json.Marshal(map[string]matchAllParams{mType: a.params})
} }
func (a *MatchAllQuery) Run(api *esapi.API, o ...func(*esapi.SearchRequest)) (res *esapi.Response, err error) {
return search(*a, api, o...)
}
func MatchAll() *MatchAllQuery { func MatchAll() *MatchAllQuery {
return &MatchAllQuery{all: true} return &MatchAllQuery{all: true}
} }