Elasticsearch

270 阅读15分钟

Elasticsearch

参考文档

mp.weixin.qq.com/s/dbBtGkFAE…

常见错误


elasticsearch各版本下载地址

kibana各版本下载地址

elasticsearch-head插件下载地址

ik分词器下载地址

启动elasticsearch

运行 elasticsearch/bin/elasticsearch.sh (windows环境)

浏览器访问 http://127.0.0.1:9200/ 可以看到如下响应

{
  "name" : "DESKTOP-31RVD33",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "gYdR1ZuyQ5WXtJHZdGKuOA",
  "version" : {
    "number" : "7.6.2",
    "build_flavor" : "default",
    "build_type" : "zip",
    "build_hash" : "ef48eb35cf30adf4db14086e8aabd07ef6fb113f",
    "build_date" : "2020-03-26T06:34:37.794943Z",
    "build_snapshot" : false,
    "lucene_version" : "8.4.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

安装head插件

elasticsearch-head下载

git clone https://github.com/mobz/elasticsearch-head.git

安装

cnpm install

运行

npm run start

浏览器访问 http://localhost:9100/


elasticsearch跨域问题

elasticsearch/config/elasticsearch.yml 中添加

http.cors.enabled: true
http.cors.allow-origin: "*"

kibana修改为中文

kibana/config/kibana.yml 中修改

i18n.locale: "zh-CN"

启动kibana

运行 kibana/bin/kibana.bat


IK分词器

IK提供两种分词算法 ik_smartik_max_word

ik_smart 最少切分

ik_max_word 最细粒度划分

GET _analyze
{
  "analyzer": "ik_smart",
  "text": "我喜欢使用elasticsearch做搜索引擎"
}
{
  "tokens" : [
    {
      "token" : "我",
      "start_offset" : 0,
      "end_offset" : 1,
      "type" : "CN_CHAR",
      "position" : 0
    },
    {
      "token" : "喜欢",
      "start_offset" : 1,
      "end_offset" : 3,
      "type" : "CN_WORD",
      "position" : 1
    },
    {
      "token" : "使用",
      "start_offset" : 3,
      "end_offset" : 5,
      "type" : "CN_WORD",
      "position" : 2
    },
    {
      "token" : "elasticsearch",
      "start_offset" : 5,
      "end_offset" : 18,
      "type" : "ENGLISH",
      "position" : 3
    },
    {
      "token" : "做",
      "start_offset" : 18,
      "end_offset" : 19,
      "type" : "CN_CHAR",
      "position" : 4
    },
    {
      "token" : "搜索引擎",
      "start_offset" : 19,
      "end_offset" : 23,
      "type" : "CN_WORD",
      "position" : 5
    }
  ]
}
GET _analyze
{
  "analyzer": "ik_max_word",
  "text": "我喜欢使用elasticsearch做搜索引擎"
}
{
  "tokens" : [
    {
      "token" : "我",
      "start_offset" : 0,
      "end_offset" : 1,
      "type" : "CN_CHAR",
      "position" : 0
    },
    {
      "token" : "喜欢",
      "start_offset" : 1,
      "end_offset" : 3,
      "type" : "CN_WORD",
      "position" : 1
    },
    {
      "token" : "使用",
      "start_offset" : 3,
      "end_offset" : 5,
      "type" : "CN_WORD",
      "position" : 2
    },
    {
      "token" : "elasticsearch",
      "start_offset" : 5,
      "end_offset" : 18,
      "type" : "ENGLISH",
      "position" : 3
    },
    {
      "token" : "做",
      "start_offset" : 18,
      "end_offset" : 19,
      "type" : "CN_CHAR",
      "position" : 4
    },
    {
      "token" : "搜索引擎",
      "start_offset" : 19,
      "end_offset" : 23,
      "type" : "CN_WORD",
      "position" : 5
    },
    {
      "token" : "搜索",
      "start_offset" : 19,
      "end_offset" : 21,
      "type" : "CN_WORD",
      "position" : 6
    },
    {
      "token" : "索引",
      "start_offset" : 20,
      "end_offset" : 22,
      "type" : "CN_WORD",
      "position" : 7
    },
    {
      "token" : "引擎",
      "start_offset" : 21,
      "end_offset" : 23,
      "type" : "CN_WORD",
      "position" : 8
    }
  ]
}

创建自己的词

编辑 elasticsearch-7.6.2\plugins\ik\config\IKAnalyzer.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
	<comment>IK Analyzer 扩展配置</comment>
	<!--用户可以在这里配置自己的扩展字典 -->
	<entry key="ext_dict">my.dic</entry>
	 <!--用户可以在这里配置自己的扩展停止词字典-->
	<entry key="ext_stopwords"></entry>
	<!--用户可以在这里配置远程扩展字典 -->
	<!-- <entry key="remote_ext_dict">words_location</entry> -->
	<!--用户可以在这里配置远程扩展停止词字典-->
	<!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>

新建my.dic, 里面配置自己的词

my.dic

王哈哈
奥利给

重启 es

GET _analyze
{
  "analyzer": "ik_smart",
  "text": "王哈哈说了句奥利给"
}
{
  "tokens" : [
    {
      "token" : "王哈哈",
      "start_offset" : 0,
      "end_offset" : 3,
      "type" : "CN_WORD",
      "position" : 0
    },
    {
      "token" : "说了",
      "start_offset" : 3,
      "end_offset" : 5,
      "type" : "CN_WORD",
      "position" : 1
    },
    {
      "token" : "句",
      "start_offset" : 5,
      "end_offset" : 6,
      "type" : "CN_CHAR",
      "position" : 2
    },
    {
      "token" : "奥利给",
      "start_offset" : 6,
      "end_offset" : 9,
      "type" : "CN_WORD",
      "position" : 3
    }
  ]
}
GET _analyze
{
  "analyzer": "ik_max_word",
  "text": "王哈哈说了句奥利给"
}
{
  "tokens" : [
    {
      "token" : "王哈哈",
      "start_offset" : 0,
      "end_offset" : 3,
      "type" : "CN_WORD",
      "position" : 0
    },
    {
      "token" : "哈哈",
      "start_offset" : 1,
      "end_offset" : 3,
      "type" : "CN_WORD",
      "position" : 1
    },
    {
      "token" : "说了",
      "start_offset" : 3,
      "end_offset" : 5,
      "type" : "CN_WORD",
      "position" : 2
    },
    {
      "token" : "句",
      "start_offset" : 5,
      "end_offset" : 6,
      "type" : "CN_CHAR",
      "position" : 3
    },
    {
      "token" : "奥利给",
      "start_offset" : 6,
      "end_offset" : 9,
      "type" : "CN_WORD",
      "position" : 4
    }
  ]
}

Restful风格

MethodURL描述
PUTlocalhost:9200/索引名称/类型名称/文档id创建文档(指定文档id)
POSTlocalhost:9200/索引名称/类型名称创建文档(随机文档id)
POSTlocalhost:9200/索引名称/类型名称/文档id/_update修改文档
DELETElocalhost:9200/索引名称/类型名称/文档id删除文档
GETlocalhost:9200/索引名称/类型名称/文档id查询文档通过文档id
POSTlocalhost:9200/索引名称/类型名称/_search查询所有数据

基本操作

GET _search
{
  "query": {
    "match_all": {}
  }
}

# 使用ik分词器
GET _analyze
{
  "analyzer": "ik_smart",
  "text": "王哈哈说了句奥利给"
}

GET _analyze
{
  "analyzer": "ik_max_word",
  "text": "王哈哈说了句奥利给"
}

# 添加数据
PUT /test/test1/1
{
  "name": "王哈哈",
  "age": 25,
  "height": 182,
  "weight": 150
}

# 指定类型
PUT /test2
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "age": {
        "type": "long"
      },
      "birthday": {
        "type": "date"
      }
    }
  }
}

# 获取索引信息
GET /test2


# 添加文档
PUT /test3/_doc/1
{
  "name": "王哈哈",
  "age": 25,
  "birthday": "1996-08-15"
}


# 更新数据,如果少写字段的话数据那么那个字段就莫得了
PUT /test3/_doc/1
{
  "name": "王哈哈",
  "age": 25,
  "birthday": "1996-08-15"
}

# 使用POST更新字段
POST /test3/_doc/1/_update
{
  "doc": {
    "age": 24
  }
}

# 获取健康信息
GET _cat/health
GET _cat/indices?v


# 删除索引
DELETE test
DELETE test2


# 删除数据
DELETE /test3/_doc/3

模糊查询(类似sql里面的like)

GET /al_work/_search
{
  "query": {
    "wildcard": {
      "subject_codes": "*0243*"
    }
  },
  "_source": ["subject_codes"],
  "size": 200
}

文档的复杂查询

GET _search
{
  "query": {
    "match_all": {}
  }
}

PUT /userinfo/_doc/2
{
  "name": "王大炮",
  "age": 24
}

POST /userinfo/_doc/1/_update
{
  "doc": {
    "age": 23
  }
}

GET /userinfo
GET /userinfo/_doc/1

GET /userinfo/_doc/_search?q=name:"王哈哈"

GET /userinfo/_doc/_search
{
  "query": {
    "match": {
      "name": "王"
    }
  }
}

# 只显示某字段(这里只显示name字段)
GET /userinfo/_doc/_search
{
  "query": {
    "match": {
      "name": "王"
    }
  },
  "_source": ["name"]
}

# 排序
GET /userinfo/_doc/_search
{
  "query": {
    "match": {
      "name": "王"
    }
  },
  "sort": [
    {
      "age": {
        "order": "desc"
      }
    }
  ]
}

# 分页
GET /userinfo/_doc/_search
{
  "query": {
    "match": {
      "name": "王"
    }
  },
  "sort": [
    {
      "age": {
        "order": "desc"
      }
    }
  ],
  "from": 0,
  "size": 2
}

# 多条件查询(must相当于mysql里面的and)
GET /userinfo/_doc/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "王哈哈"
          }
        },
        {
          "match": {
            "age": 23
          }
        }
      ]
    }
  }
}


# 多条件查询
GET /al_work/_count
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "publish_flag": "1"
          }
        }
      ],
      "filter": {
        "range": {
          "create_date": {
            "lt": "2022-02-03"
          }
        }
      }
    }
  }
}

# 或 should(or) 
GET /userinfo/_doc/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "name": "哈哈"
          }
        },
        {
          "match": {
            "age": 24
          }
        }
      ]
    }
  }
}

# 否定条件
GET /userinfo/_doc/_search
{
  "query": {
    "bool": {
      "must_not": [
        {
          "match": {
            "age": 24
          }
        }
      ]
    }
  }
}

# 过滤条件 gt大于  lt小于  gte大于等于 lte 小于等于
GET /userinfo/_doc/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "王"
          }
        }
      ],
      "filter": {
        "range": {
          "age": {
            "lt": 24
          }
        }
      }
    }
  }
}

# 大于等于1岁小于等于100GET /userinfo/_doc/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "王"
          }
        }
      ],
      "filter": {
        "range": {
          "age": {
            "gte": 1,
            "lte": 100
          }
        }
      }
    }
  }
}

# 列表数据查询多个条件空格隔开
# 比如 tags ["音乐", "旅游", "学习"]
GET /userinfo/_doc/_serach
{
  "query": {
    "match": {
      "tags": "旅游 学习"
    }
  }
}


# 精确查询
# term查询是直接经过倒排索引指定的词条进行精确查找的
# 关于分词
# term - 精确查询
# match - 使用分词器解析查询

# 两个类型 text(分词器会解析), keyword(不会解析)
PUT /testdb
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "desc": {
        "type": "keyword"
      }
    }
  }
}

PUT /testdb/_doc/1
{
  "name": "王哈哈",
  "desc": "王哈哈的描述信息"
}

PUT /testdb/_doc/2
{
  "name": "迪丽热巴",
  "desc": "迪丽热巴的描述信息"
}


GET /testdb/_search
{
  "query": {
    "term": {
      "name": "王"
    }
  }
}

GET /testdb/_search
{
  "query": {
    "term": {
      "desc": "迪丽热巴的描述信息"
    }
  }
}

# 精确查询多个值
GET /testdb/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "term": {
            "desc": "王哈哈的描述信息"
          }
        },
        {
          "term": {
            "desc": "迪丽热巴的描述信息"
          }
        }
      ]
    }
  }
}

高亮查询

# 高亮显示
GET /userinfo/_search
{
  "query": {
    "match": {
      "name": "王"
    }
  },
  "highlight": {
    "fields": {
      "name": {}
    }
  }
}

# 自定义高亮标签
GET /userinfo/_search
{
  "query": {
    "match": {
      "name": "王"
    }
  },
  "highlight": {
    "pre_tags": "<p class='key' style='color:red'>", 
    "post_tags": "</p>", 
    "fields": {
      "name": {}
    }
  }
}

设置最大索引值

PUT /al_work/_settings?pretty
{
  "index":{
    "max_result_window":1000000000
  }
}

golang操作elasticsearch

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
	"reflect"
	"time"

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

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"`
}

func main() {
	errorlog := log.New(os.Stdout, "APP ", log.LstdFlags)

	// Obtain a client. You can also provide your own HTTP client here.
	client, err := elastic.NewClient(elastic.SetErrorLog(errorlog))
	// Trace request and response details like this
	// client, err := elastic.NewClient(elastic.SetTraceLog(log.New(os.Stdout, "", 0)))
	if err != nil {
		// Handle error
		panic(err)
	}

	// Ping the Elasticsearch server to get e.g. the version number
	info, code, err := client.Ping("http://127.0.0.1:9200").Do(context.Background())
	if err != nil {
		// Handle error
		panic(err)
	}
	fmt.Printf("Elasticsearch returned with code %d and version %s\n", code, info.Version.Number)

	// Getting the ES version number is quite common, so there's a shortcut
	esversion, err := client.ElasticsearchVersion("http://127.0.0.1:9200")
	if err != nil {
		// Handle error
		panic(err)
	}
	fmt.Printf("Elasticsearch version %s\n", esversion)

	// Use the IndexExists service to check if a specified index exists.
	exists, err := client.IndexExists("twitter").Do(context.Background())
	if err != nil {
		// Handle error
		panic(err)
	}
	if !exists {
		// Create a new index.
		mapping := `
{
	"settings":{
		"number_of_shards":1,
		"number_of_replicas":0
	},
	"mappings":{
		"doc":{
			"properties":{
				"user":{
					"type":"keyword"
				},
				"message":{
					"type":"text",
					"store": true,
					"fielddata": true
				},
                "retweets":{
                    "type":"long"
                },
				"tags":{
					"type":"keyword"
				},
				"location":{
					"type":"geo_point"
				},
				"suggest_field":{
					"type":"completion"
				}
			}
		}
	}
}
`
		createIndex, err := client.CreateIndex("twitter").Body(mapping).IncludeTypeName(true).Do(context.Background())
		if err != nil {
			// Handle error
			panic(err)
		}
		if !createIndex.Acknowledged {
			// Not acknowledged
		}
	}

	// Index a tweet (using JSON serialization)
	tweet1 := Tweet{User: "olivere", Message: "Take Five", Retweets: 0}
	put1, err := client.Index().
		Index("twitter").
		Type("doc").
		Id("1").
		BodyJson(tweet1).
		Do(context.Background())
	if err != nil {
		// Handle error
		panic(err)
	}
	fmt.Printf("Indexed tweet %s to index %s, type %s\n", put1.Id, put1.Index, put1.Type)

	// Index a second tweet (by string)
	tweet2 := `{"user" : "olivere", "message" : "It's a Raggy Waltz"}`
	put2, err := client.Index().
		Index("twitter").
		Type("doc").
		Id("2").
		BodyString(tweet2).
		Do(context.Background())
	if err != nil {
		// Handle error
		panic(err)
	}
	fmt.Printf("Indexed tweet %s to index %s, type %s\n", put2.Id, put2.Index, put2.Type)

	// Get tweet with specified ID
	get1, err := client.Get().
		Index("twitter").
		Type("doc").
		Id("1").
		Do(context.Background())
	if err != nil {
		switch {
		case elastic.IsNotFound(err):
			panic(fmt.Sprintf("Document not found: %v", err))
		case elastic.IsTimeout(err):
			panic(fmt.Sprintf("Timeout retrieving document: %v", err))
		case elastic.IsConnErr(err):
			panic(fmt.Sprintf("Connection problem: %v", err))
		default:
			// Some other kind of error
			panic(err)
		}
	}
	fmt.Printf("Got document %s in version %d from index %s, type %s\n", get1.Id, get1.Version, get1.Index, get1.Type)

	// Flush to make sure the documents got written.
	_, err = client.Flush().Index("twitter").Do(context.Background())
	if err != nil {
		panic(err)
	}

	// Search with a term query
	termQuery := elastic.NewTermQuery("user", "olivere")
	searchResult, err := client.Search().
		Index("twitter").        // search in index "twitter"
		Query(termQuery).        // specify the query
		Sort("user", true).      // sort by "user" field, ascending
		From(0).Size(10).        // take documents 0-9
		Pretty(true).            // pretty print request and response JSON
		Do(context.Background()) // execute
	if err != nil {
		// Handle error
		panic(err)
	}

	// searchResult is of type SearchResult and returns hits, suggestions,
	// and all kinds of other information from Elasticsearch.
	fmt.Printf("Query took %d milliseconds\n", searchResult.TookInMillis)

	// Each is a convenience function that iterates over hits in a search result.
	// It makes sure you don't need to check for nil values in the response.
	// However, it ignores errors in serialization. If you want full control
	// over iterating the hits, see below.
	var ttyp Tweet
	for _, item := range searchResult.Each(reflect.TypeOf(ttyp)) {
		t := item.(Tweet)
		fmt.Printf("Tweet by %s: %s\n", t.User, t.Message)
	}
	// TotalHits is another convenience function that works even when something goes wrong.
	fmt.Printf("Found a total of %d tweets\n", searchResult.TotalHits())

	// Here's how you iterate through results with full control over each step.
	if searchResult.Hits.TotalHits > 0 {
		fmt.Printf("Found a total of %d tweets\n", searchResult.Hits.TotalHits)

		// Iterate through results
		for _, hit := range searchResult.Hits.Hits {
			// hit.Index contains the name of the index

			// Deserialize hit.Source into a Tweet (could also be just a map[string]interface{}).
			var t Tweet
			err := json.Unmarshal(*hit.Source, &t)
			if err != nil {
				// Deserialization failed
			}

			// Work with tweet
			fmt.Printf("Tweet by %s: %s\n", t.User, t.Message)
		}
	} else {
		// No hits
		fmt.Print("Found no tweets\n")
	}

	// Update a tweet by the update API of Elasticsearch.
	// We just increment the number of retweets.
	script := elastic.NewScript("ctx._source.retweets += params.num").Param("num", 1)
	update, err := client.Update().Index("twitter").Type("doc").Id("1").
		Script(script).
		Upsert(map[string]interface{}{"retweets": 0}).
		Do(context.Background())
	if err != nil {
		// Handle error
		panic(err)
	}
	fmt.Printf("New version of tweet %q is now %d", update.Id, update.Version)

	// ...

	// Delete an index.
	deleteIndex, err := client.DeleteIndex("twitter").Do(context.Background())
	if err != nil {
		// Handle error
		panic(err)
	}
	if !deleteIndex.Acknowledged {
		// Not acknowledged
	}
}

新版

创建索引

创建一个索引名为shopping

PUT /shopping

返回结果

{
  "acknowledged" : true,
  "shards_acknowledged" : true,
  "index" : "shopping"
}

再次发送创建请求则会报错

{
  "error" : {
    "root_cause" : [
      {
        "type" : "resource_already_exists_exception",
        "reason" : "index [shopping/aE96nccCSmOXYZG9aUnmyA] already exists",
        "index_uuid" : "aE96nccCSmOXYZG9aUnmyA",
        "index" : "shopping"
      }
    ],
    "type" : "resource_already_exists_exception",
    "reason" : "index [shopping/aE96nccCSmOXYZG9aUnmyA] already exists",
    "index_uuid" : "aE96nccCSmOXYZG9aUnmyA",
    "index" : "shopping"
  },
  "status" : 400
}

获取索引信息

GET /shopping

返回结果

{
  "shopping" : {
    "aliases" : { },
    "mappings" : { },
    "settings" : {
      "index" : {
        "routing" : {
          "allocation" : {
            "include" : {
              "_tier_preference" : "data_content"
            }
          }
        },
        "number_of_shards" : "1",
        "provided_name" : "shopping",
        "creation_date" : "1638604381990",
        "number_of_replicas" : "1",
        "uuid" : "aE96nccCSmOXYZG9aUnmyA",
        "version" : {
          "created" : "7150299"
        }
      }
    }
  }
}

获取所有索引

GET /_cat/indices

// 查看详细信息可以加 ?v 参数
GET /_cat/indices?v

返回结果

green  open .geoip_databases                cWErzuSJTe2z4x-SYRy4Aw 1 0 43   38  43.6mb  43.6mb
green  open .apm-custom-link                0BoeKbRhRCCKFpR7ordtYQ 1 0  0    0    208b    208b
green  open .apm-agent-configuration        B_mZp-gCSXa2EVJbjfj0hQ 1 0  0    0    208b    208b
green  open .kibana-event-log-7.15.2-000001 iwXccJQCSlyEm5o0fwzu_g 1 0  5    0  23.8kb  23.8kb
green  open .kibana_7.15.2_001              kCAw_wl8Tkm0tkCtZmXC_g 1 0 34    9   9.3mb   9.3mb
yellow open shopping                        aE96nccCSmOXYZG9aUnmyA 1 1  0    0    208b    208b
green  open .tasks                          rsMEEgDXRC61HqKD3yU5qA 1 0  8    0  36.4kb  36.4kb
green  open .kibana_task_manager_7.15.2_001 sMrOZuqzSwK6Wr6S-LJ58w 1 0 15 2571 431.4kb 431.4kb

删除索引

DELETE /shopping

返回结果

{
  "acknowledged" : true
}

向索引中添加数据

POST /shopping/_doc
{
  "title": "小米手机",
  "category": "小米",
  "images": "http://xxxxx/xm.jpg",
  "price": 3999.00
}

返回结果

{
  "_index" : "shopping",
  "_type" : "_doc",
  "_id" : "s1B-hH0Bkifry_7pwzKn",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}

向索引中添加数据-自定义ID

POST /shopping/_doc/1001
{
  "title": "小米手机",
  "category": "小米",
  "images": "http://xxxxx/xm.jpg",
  "price": 3999.00
}

返回结果

{
  "_index" : "shopping",
  "_type" : "_doc",
  "_id" : "1001",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 1,
  "_primary_term" : 1
}

查询指定ID文档

GET /shopping/_doc/1001

返回结果

{
  "_index" : "shopping",
  "_type" : "_doc",
  "_id" : "1001",
  "_version" : 2,
  "_seq_no" : 2,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "title" : "小米手机",
    "category" : "小米",
    "images" : "http://xxxxx/xm.jpg",
    "price" : 3999.0
  }
}

找不到返回

{
  "_index" : "shopping",
  "_type" : "_doc",
  "_id" : "1005",
  "found" : false
}

查询指定索引下的全部文档

GET /shopping/_search

返回结果

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "shopping",
        "_type" : "_doc",
        "_id" : "s1B-hH0Bkifry_7pwzKn",
        "_score" : 1.0,
        "_source" : {
          "title" : "小米手机",
          "category" : "小米",
          "images" : "http://xxxxx/xm.jpg",
          "price" : 3999.0
        }
      },
      {
        "_index" : "shopping",
        "_type" : "_doc",
        "_id" : "1001",
        "_score" : 1.0,
        "_source" : {
          "title" : "小米手机",
          "category" : "小米",
          "images" : "http://xxxxx/xm.jpg",
          "price" : 3999.0
        }
      }
    ]
  }
}

took 耗费时间(单位毫秒)

timed_out 是否超时

hits 命中的结果

覆盖数据

PUT /shopping/_doc/1001
{
  "title" : "黑鲨4Pro",
  "category" : "小米",
  "price" : 5999.0
}

返回结果

{
  "_index" : "shopping",
  "_type" : "_doc",
  "_id" : "1001",
  "_version" : 3,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 3,
  "_primary_term" : 1
}

修改数据

POST /shopping/_update/1001
{
  "doc": {
    "price": 8565.00
  }
}

返回结果

{
  "_index" : "shopping",
  "_type" : "_doc",
  "_id" : "1001",
  "_version" : 4,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 4,
  "_primary_term" : 1
}

删除数据

DELETE /shopping/_doc/1001

返回结果

{
  "_index" : "shopping",
  "_type" : "_doc",
  "_id" : "1001",
  "_version" : 5,
  "result" : "deleted",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 5,
  "_primary_term" : 1
}

条件查询-请求路径的方式

查询 category 字段值为 小米 的数据

GET /shopping/_search?q=category:小米

返回结果

{
  "took" : 828,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 0.21072102,
    "hits" : [
      {
        "_index" : "shopping",
        "_type" : "_doc",
        "_id" : "s1B-hH0Bkifry_7pwzKn",
        "_score" : 0.21072102,
        "_source" : {
          "title" : "小米手机",
          "category" : "小米",
          "images" : "http://xxxxx/xm.jpg",
          "price" : 3999.0
        }
      },
      {
        "_index" : "shopping",
        "_type" : "_doc",
        "_id" : "1001",
        "_score" : 0.21072102,
        "_source" : {
          "title" : "黑鲨4Pro",
          "category" : "小米",
          "price" : 5999.0
        }
      }
    ]
  }
}

条件查询-请求体的方式

GET /shopping/_search
{
  "query": {
    "match": {
      "category": "小米"
    }
  }
}

返回结果

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 0.36464313,
    "hits" : [
      {
        "_index" : "shopping",
        "_type" : "_doc",
        "_id" : "s1B-hH0Bkifry_7pwzKn",
        "_score" : 0.36464313,
        "_source" : {
          "title" : "小米手机",
          "category" : "小米",
          "images" : "http://xxxxx/xm.jpg",
          "price" : 3999.0
        }
      },
      {
        "_index" : "shopping",
        "_type" : "_doc",
        "_id" : "1001",
        "_score" : 0.36464313,
        "_source" : {
          "title" : "黑鲨4Pro",
          "category" : "小米",
          "price" : 5999.0
        }
      }
    ]
  }
}

查询全部数据

GET /shopping/_search
{
  "query": {
    "match_all": {}
  }
}

返回结果

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "shopping",
        "_type" : "_doc",
        "_id" : "s1B-hH0Bkifry_7pwzKn",
        "_score" : 1.0,
        "_source" : {
          "title" : "小米手机",
          "category" : "小米",
          "images" : "http://xxxxx/xm.jpg",
          "price" : 3999.0
        }
      },
      {
        "_index" : "shopping",
        "_type" : "_doc",
        "_id" : "1001",
        "_score" : 1.0,
        "_source" : {
          "title" : "黑鲨4Pro",
          "category" : "小米",
          "price" : 5999.0
        }
      }
    ]
  }
}

分页查询

GET /shopping/_search
{
  "query": {
    "match_all": {}
  },
  "from": 0,
  "size":1
}

from 当前页起始位置

size 每页数据条数

返回结果

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "shopping",
        "_type" : "_doc",
        "_id" : "s1B-hH0Bkifry_7pwzKn",
        "_score" : 1.0,
        "_source" : {
          "title" : "小米手机",
          "category" : "小米",
          "images" : "http://xxxxx/xm.jpg",
          "price" : 3999.0
        }
      }
    ]
  }
}

from 计算方式 (页码-1)*size

from = (页码-1) * size

查询结果字段过滤

GET /shopping/_search
{
  "query": {
    "match_all": {}
  },
  "_source": ["title"]
}

返回结果

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "shopping",
        "_type" : "_doc",
        "_id" : "s1B-hH0Bkifry_7pwzKn",
        "_score" : 1.0,
        "_source" : {
          "title" : "小米手机"
        }
      },
      {
        "_index" : "shopping",
        "_type" : "_doc",
        "_id" : "1001",
        "_score" : 1.0,
        "_source" : {
          "title" : "黑鲨4Pro"
        }
      }
    ]
  }
}

排序

GET /shopping/_search
{
  "query": {
    "match_all": {}
  },
  "sort": {
    "price": {
      "order": "asc"
    }
  }
}

order 取值 asc 升序, desc 降序

返回结果

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [
      {
        "_index" : "shopping",
        "_type" : "_doc",
        "_id" : "1001",
        "_score" : null,
        "_source" : {
          "title" : "黑鲨4Pro",
          "category" : "小米",
          "price" : 5999.0
        },
        "sort" : [
          5999.0
        ]
      },
      {
        "_index" : "shopping",
        "_type" : "_doc",
        "_id" : "s1B-hH0Bkifry_7pwzKn",
        "_score" : null,
        "_source" : {
          "title" : "小米手机",
          "category" : "小米",
          "images" : "http://xxxxx/xm.jpg",
          "price" : 3999.0
        },
        "sort" : [
          3999.0
        ]
      }
    ]
  }
}

多条件查询-多个条件同时满足(must)

GET /shopping/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "category": "小米"
          }
        },
        {
          "match": {
            "price": 5999.00
          }
        }
      ]
    }
  }
}

返回结果

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.3646431,
    "hits" : [
      {
        "_index" : "shopping",
        "_type" : "_doc",
        "_id" : "1001",
        "_score" : 1.3646431,
        "_source" : {
          "title" : "黑鲨4Pro",
          "category" : "小米",
          "price" : 5999.0
        }
      }
    ]
  }
}

多条件查询-should(类似or)

GET /shopping/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "category": "小米"
          }
        },
        {
          "match": {
            "category": "黑鲨4Pro"
          }
        }
      ]
    }
  }
}

返回结果

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 0.36464313,
    "hits" : [
      {
        "_index" : "shopping",
        "_type" : "_doc",
        "_id" : "s1B-hH0Bkifry_7pwzKn",
        "_score" : 0.36464313,
        "_source" : {
          "title" : "小米手机",
          "category" : "小米",
          "images" : "http://xxxxx/xm.jpg",
          "price" : 3999.0
        }
      },
      {
        "_index" : "shopping",
        "_type" : "_doc",
        "_id" : "1001",
        "_score" : 0.36464313,
        "_source" : {
          "title" : "黑鲨4Pro",
          "category" : "小米",
          "price" : 5999.0
        }
      }
    ]
  }
}

范围查询-大于小于-大于等于...

GET /shopping/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "category": "小米"
          }
        },
        {
          "match": {
            "category": "黑鲨4Pro"
          }
        }
      ],
      "filter": {
        "range": {
          "price": {
            "gt": 5000
          }
        }
      }
    }
  }
}

返回结果

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.36464313,
    "hits" : [
      {
        "_index" : "shopping",
        "_type" : "_doc",
        "_id" : "1001",
        "_score" : 0.36464313,
        "_source" : {
          "title" : "黑鲨4Pro",
          "category" : "小米",
          "price" : 5999.0
        }
      }
    ]
  }
}

精确查询-精确匹配-完全匹配(match_phrase)

这里我们查询小黑,由于分词后可以匹配到"小米","黑鲨",所以是可以查到值的

GET /shopping/_search
{
  "query": {
    "match": {
      "title": "小黑"
    }
  }
}

返回结果

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 0.7361701,
    "hits" : [
      {
        "_index" : "shopping",
        "_type" : "_doc",
        "_id" : "1001",
        "_score" : 0.7361701,
        "_source" : {
          "title" : "黑鲨4Pro",
          "category" : "小米",
          "price" : 5999.0
        }
      },
      {
        "_index" : "shopping",
        "_type" : "_doc",
        "_id" : "s1B-hH0Bkifry_7pwzKn",
        "_score" : 0.6548753,
        "_source" : {
          "title" : "小米手机",
          "category" : "小米",
          "images" : "http://xxxxx/xm.jpg",
          "price" : 3999.0
        }
      }
    ]
  }
}

改用 match_phrase

GET /shopping/_search
{
  "query": {
    "match_phrase": {
      "title": "小米"
    }
  }
}

返回结果

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.3097506,
    "hits" : [
      {
        "_index" : "shopping",
        "_type" : "_doc",
        "_id" : "s1B-hH0Bkifry_7pwzKn",
        "_score" : 1.3097506,
        "_source" : {
          "title" : "小米手机",
          "category" : "小米",
          "images" : "http://xxxxx/xm.jpg",
          "price" : 3999.0
        }
      }
    ]
  }
}

高亮显示

GET /shopping/_search
{
  "query": {
    "match_phrase": {
      "title": "小米"
    }
  },
  "highlight": {
    "fields": {
      "title": {}
    }
  }
}

返回结果

{
  "took" : 33,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.3097506,
    "hits" : [
      {
        "_index" : "shopping",
        "_type" : "_doc",
        "_id" : "s1B-hH0Bkifry_7pwzKn",
        "_score" : 1.3097506,
        "_source" : {
          "title" : "小米手机",
          "category" : "小米",
          "images" : "http://xxxxx/xm.jpg",
          "price" : 3999.0
        },
        "highlight" : {
          "title" : [
            "<em>小</em><em>米</em>手机"
          ]
        }
      }
    ]
  }
}

聚合查询-分组

# 聚合查询
GET /shopping/_search
{
  "aggs": {
    "price_group": {
      "terms": {
        "field": "price"
      }
    }
  }
}

返回结果

{
  "took" : 6,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "shopping",
        "_type" : "_doc",
        "_id" : "s1B-hH0Bkifry_7pwzKn",
        "_score" : 1.0,
        "_source" : {
          "title" : "小米手机",
          "category" : "小米",
          "images" : "http://xxxxx/xm.jpg",
          "price" : 3999.0
        }
      },
      {
        "_index" : "shopping",
        "_type" : "_doc",
        "_id" : "1001",
        "_score" : 1.0,
        "_source" : {
          "title" : "黑鲨4Pro",
          "category" : "小米",
          "price" : 5999.0
        }
      }
    ]
  },
  "aggregations" : {
    "price_group" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : 3999.0,
          "doc_count" : 1
        },
        {
          "key" : 5999.0,
          "doc_count" : 1
        }
      ]
    }
  }
}

聚合查询-分组-不显示原始数据

GET /shopping/_search
{
  "aggs": {
    "price_group": {
      "terms": {
        "field": "price"
      }
    }
  },
  "size": 0
}

返回结果

{
  "took" : 7,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "price_group" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : 3999.0,
          "doc_count" : 1
        },
        {
          "key" : 5999.0,
          "doc_count" : 1
        }
      ]
    }
  }
}

聚合查询-平均值

{
  "aggs": {
    "price_avg": {
      "avg": {
        "field": "price"
      }
    }
  },
  "size": 0
}

返回结果

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "price_avg" : {
      "value" : 4999.0
    }
  }
}

聚合查询-最大值

GET /shopping/_search
{
  "aggs": {
    "price_avg": {
      "max": {
        "field": "price"
      }
    }
  },
  "size": 0
}

返回值

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "price_avg" : {
      "value" : 5999.0
    }
  }
}

映射

// 创建一个索引
PUT /user

// 映射 mapping
PUT /user/_mapping
{
  "properties": {
    "name": {
      "type": "text",
      "index": true
    },
    "sex": {
      "type": "keyword",
      "index": true
    },
    "tel": {
      "type": "keyword",
      "index": false
    }
  }
}
  • type
    • text 可以分词
    • keyword 不能分词,只能完整匹配
  • index 是否可以被索引

返回结果

{
  "acknowledged" : true
}

查看 mapping

GET /user/_mapping

返回结果

{
  "user" : {
    "mappings" : {
      "properties" : {
        "name" : {
          "type" : "text"
        },
        "sex" : {
          "type" : "keyword"
        },
        "tel" : {
          "type" : "keyword",
          "index" : false
        }
      }
    }
  }
}

操作

// 添加两条数据
POST /user/_doc
{
  "name": "张三",
  "sex": "男",
  "tel": "18300005588"
}

POST /user/_doc
{
  "name": "张飞",
  "sex": "男的",
  "tel": "15800008899"
}

// 查询数据, mapping 是text类型
GET /user/_search
{
  "query": {
    "match": {
      "name": "飞"
    }
  }
}

GET /user/_search
{
  "query": {
    "match": {
      "name": "张"
    }
  }
}

// 查询数据, mapping 是keyword类型
GET /user/_search
{
  "query": {
    "match": {
      "sex": "男的"
    }
  }
}

// index是false 不可被索引, 查询会报错
GET /user/_search
{
  "query": {
    "match": {
      "tel": "18300005588"
    }
  }
}

查询指定索引数据总量

GET /al_artist/_count

返回结果

{
  "count" : 12979,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  }
}

Elasticsearch集群部署

节点一

vim elasticsearch.yml

# 集群名称,集群中的每个节点名称必须一样
cluster.name: es
# 该节点有机会成为master节点
node.master: true
# 该节点可以存储数据
node.data: true
# 节点名称,不能重复
node.name: node-1
# 允许所有节点访问
network.host: 0.0.0.0 

# http端口
http.port: 9201

# TCP的默认监听端口,默认 9300
transport.tcp.port: 9301

# 候选主节点的设备地址,在开启服务后可以被选为主节点
discovery.seed_hosts: ["127.0.0.1:9301","127.0.0.1:9302","127.0.0.1:9303"]

# 初始化一个新的集群时需要此配置来选举master
cluster.initial_master_nodes: ["node-1", "node-2","node-3"]

# 最大集群节点数
node.max_local_storage_nodes: 3

# 跨域配置
http.cors.enabled: true
http.cors.allow-origin: "*"

节点二

vim elsticsearch.yml

# 集群名称,集群中的每个节点名称必须一样
cluster.name: es
# 该节点有机会成为master节点
node.master: true
# 该节点可以存储数据
node.data: true
# 节点名称,不能重复
node.name: node-2
# 允许所有节点访问
network.host: 0.0.0.0 

# http端口
http.port: 9202

# TCP的默认监听端口,默认 9300
transport.tcp.port: 9302

# 候选主节点的设备地址,在开启服务后可以被选为主节点
discovery.seed_hosts: ["127.0.0.1:9301","127.0.0.1:9302","127.0.0.1:9303"]

# 初始化一个新的集群时需要此配置来选举master
cluster.initial_master_nodes: ["node-1", "node-2","node-3"]

# 最大集群节点数
node.max_local_storage_nodes: 3

# 跨域配置
http.cors.enabled: true
http.cors.allow-origin: "*"

节点三

vim elsticsearch.yml

# 集群名称,集群中的每个节点名称必须一样
cluster.name: es
# 该节点有机会成为master节点
node.master: true
# 该节点可以存储数据
node.data: true
# 节点名称,不能重复
node.name: node-3
# 允许所有节点访问
network.host: 0.0.0.0 

# http端口
http.port: 9203

# TCP的默认监听端口,默认 9300
transport.tcp.port: 9303

# 候选主节点的设备地址,在开启服务后可以被选为主节点
discovery.seed_hosts: ["127.0.0.1:9301","127.0.0.1:9302","127.0.0.1:9303"]

# 初始化一个新的集群时需要此配置来选举master
cluster.initial_master_nodes: ["node-1", "node-2","node-3"]

# 最大集群节点数
node.max_local_storage_nodes: 3

# 跨域配置
http.cors.enabled: true
http.cors.allow-origin: "*"

查看集群的状态

http://ip:9201/_cluster/health

Elasticsearch备份与恢复