This is the 17th day of my participation in the August More text Challenge. For details, see: August More Text Challenge
Introduction to the
Elasticsearch is a distributed, RESTful search and data analysis engine that is fast, can carry petabytes of data, and is highly reliable. A single cluster can run hundreds of nodes simultaneously
What can be done?
What can ElasticSearch do now? Officials have given the following complete list of solutions
In actual business, it is mostly used as log server and search service
task
Here, we mainly use the GO language to call SDK to realize the addition, deletion, change and search of ES, and we are familiar with the search operation of ES API
Installation Tools
In order to write code quickly, we use Docker to install elasticSearch. In addition to installing ElasticSearch, we also install monitoring tools and query tools to help with efficient development
Centos quick docker portal installation: juejin.cn/post/684490…
Install the elasticsearch
Create a network with containers within the same network, Docker run -d --name elasticSearch docker run -d --name ElasticSearch --net somenetwork -p9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.62.
Copy the code
Install the ES query tool dejavu
docker run -p 1358:1358 -d --name dejavu appbaseio/dejavu
Copy the code
Install the ES monitoring tool
docker run -d --name cerebro -p 9000:9000 lmenezes/cerebro
Copy the code
Install the Kibana query tool
docker run -d --name kibana --net somenetwork -p 5601:5601 kibana:7.62.
Copy the code
API example
In fact, there are two GO language ES clients. One is the official one, and the other is the olivere one. Currently, olivere is more popular than the official one
Olivere Client address: github.com/olivere/ela…
Olivere document address: olivere. Making. IO/elastic /
Es official client address: github.com/elastic/go-…
Since we are using the ES7 version, specify this when introducing the client
import "github.com/olivere/elastic/v7"
Copy the code
The global variable
Set global variables directly for objects used repeatedly in subsequent methods to reduce code redundancy
var (
client *elastic.Client
url = "http://es-ip:9200"
ctx = context.Background()
)
Copy the code
Creating a client
SetSniff this should be turned off since we are using Docker to start es and there is no such problem if it is installed by RPM
Write an init function to execute client creation and status detection at project start. Then you can concentrate on writing
func init() {
client, _ = elastic.NewClient(elastic.SetSniff(false), elastic.SetURL(url))
// Test the state of the ES connection
_, _, err := client.Ping(url).Do(ctx)
iferr ! = nil { log.Println("Connection to ES failed", err)
}
// Check the current version of es
version, err := client.ElasticsearchVersion(url)
iferr ! = nil { log.Println("Error querying es version", err)
}
log.Println("Elasticsearch version: ", version)
}
Copy the code
Create indexes and structures
The index mapping for ES is specified at creation time and cannot be updated later. It is best to specify it at design time
The mapping structure This structure has the mappings in the official document. Tweet. The properties directly remove the tweet here. Because ES7 can’t specify a type
const mapping = ` { "settings":{ "number_of_shards": 1, "number_of_replicas": 0 }, "mappings":{ "properties":{ "user":{ "type":"keyword" }, "message":{ "type":"text", "store": true, "fielddata": true }, "image":{ "type":"keyword" }, "created":{ "type":"date" }, "tags":{ "type":"keyword" }, "location":{ "type":"geo_point" }, "suggest_field":{ "type":"completion" } } } }`
Copy the code
Create index function
Es7 version does not have type, default is _doc, no need to create methods now, query, etc. Type method, or call the following method directly
func indexCreate(action string) {
// Check whether the index exists
exists, err := client.IndexExists("twitter").Do(ctx)
iferr ! = nil { log.Fatal(err) }// The index does not exist
if! exists { indexCreate,err := client.CreateIndex("twitter").BodyString(mapping).Do(ctx)
iferr ! = nil { log.Println("Failed to create index", err)
}
if! indexCreate.Acknowledged { log.Println("Failed to create")}}}Copy the code
Write data
Before we can write data, we need a structure
type Tweet struct {
User string `json:"user"`
Message string `json:"message"`
Retweets int `json:"retweets"`
Image string `json:"image,omitempty"`
Created time.Time `json:"created,omitempty"`
Tags []string `json:"tags,omitempty"`
Location string `json:"location,omitempty"`
Suggest *elastic.SuggestField `json:"suggest_field,omitempty"`
}
Copy the code
For testing convenience, directly loop through 100 pieces of data, or more, not every field will write data, depending on the case
func createTweet() {
// Define a dead piece of data
tweet := Tweet{User: "olivere".Message: "Take Five".Retweets: 0.Image: "icon".Tags: []string{"music"."book"}}
res, err := client.Index().Index("twitter").Id("1").BodyJson(tweet).Do(ctx)
iferr ! = nil { log.Println("Data write failed", err)
}
fmt.Printf("Indexed tweet %s to index s%s, type %s\n", res.Id, res.Index, res.Type)
// Loop 100 pieces of data
for i := 1; i < 100; i++ {
tweet := Tweet{User: "olivere".Message: "Take Five".Retweets: i, Image: "icon".Created: time.Now(), Tags: []string{"music"."book"}}
_, _ = client.Index().Index("twitter").Id(strconv.Itoa(i)).BodyJson(tweet).Do(context.Background())
}
/ / brush plate
_, _ = client.Flush().Index("twitter").Do(ctx)
}
Copy the code
To get the data
Specify the data ID, get a piece of data, data exists in the Source, the data is decoded into a structure output
func getTweet() {
res, _ := client.Get().Index("twitter").Id("3").Do(ctx)
if res.Found {
fmt.Printf("Got document %s in version %d from index %s, type %s\n", res.Id, res.Version, res.Index, res.Type)
var tweet Tweet
_ = json.Unmarshal(res.Source, &tweet)
fmt.Println("Data content:",tweet)
}
}
Copy the code
Delete the data
To delete a piece of data, specify the data ID
func deleteTweet() {
result, _ := client.Delete().Index("twitter").Id("3").Do(ctx)
fmt.Println(result.Result)
}
Copy the code
Update the data
Update the data of a certain field, specify the ID, update one
func updateTweet() {
result, _ := client.Update().Index("twitter").Id("99").Doc(map[string]interface{}{"image": "image"}).Do(ctx)
fmt.Println(result.Result)
}
Copy the code
A few simple CURD examples are done here, but ES is a search server, so let’s look at the SEARCH API
Search API
In the same demo here, to avoid code redundancy, do not return the err value directly, remember to add production environment, error handling is a necessary part of the process
Common methods
Because when you call the search method, the values often have to be processed and extracted to write a function to make the code a little cleaner
(struct (item.(struct))); (struct (item.(struct))
func searchValue(res *elastic.SearchResult) {
var tweet Tweet
// Use reflection to get Struct field information
for _, item := range res.Each(reflect.TypeOf(tweet)) {
// Force the interface type to be struct
t := item.(Tweet)
fmt.Printf("%#v\n", t)
}
}
Copy the code
Search all
Note that res.hits. Hits returns only 10 results by default. If you want to display more results, you need to call the search method: search (“index”).size(100).do
func searchAll() {
res, _ := client.Search("twitter").Do(ctx)
searchValue(res)
}
Copy the code
Field search
Searches for a value of a specified field
func searchField() {
stringQuery := elastic.NewQueryStringQuery("image:icon")
res, _ := client.Search("twitter").Query(stringQuery).Do(ctx)
searchValue(res)
}
Copy the code
Conditions of the search
Two conditions were set for search, one was the field value image/icon, the other was retweets greater than 33
func searchCondition() {
boolQuery := elastic.NewBoolQuery()
boolQuery.Must(elastic.NewMatchQuery("image"."icon"))
boolQuery.Filter(elastic.NewRangeQuery("retweets").Gt(33))
res, _ := client.Search("twitter").Query(boolQuery).Do(ctx)
searchValue(res)
}
Copy the code
A phrase search
Phrase search is to search for a single word or more words connected together in a large section of language
func searchPhrase() {
phraseQuery := elastic.NewMatchPhraseQuery("message"."Take")
res, _ := client.Search("twitter").Query(phraseQuery).Do(ctx)
searchValue(res)
}
Copy the code
Combination of search
Combinatorial searches are common in production environments, because the user is typing one word or a set of words, and all we need to do is find what the user wants from multiple fields
func searchGroup() {
phraseGroup := elastic.NewMatchPhraseQuery("message"."Five")
stringGroup := elastic.NewQueryStringQuery("image:icon")
res, _ := client.Search("twitter").Query(phraseGroup).Query(stringGroup).Do(ctx)
searchValue(res)
}
Copy the code
conclusion
The above examples run down, can feel olivere client is still very powerful, basically can meet our daily use. And in the data structure mapping method is also implemented, we do not need to use a field one by one
The olivere website lists the apis that have been implemented, very multi-portal: github.com/olivere/ela…