一:初步检索
1. _cat
- GET
127.0.0.1:9200/_cat/nodes
:查看所有节点 - GET
127.0.0.1:9200/_cat/health
:查看 es 健康状况 - GET
127.0.0.1:9200/_cat/master
:查看主节点 - GET
127.0.0.1:9200/_cat/indices
:查看所有索引 show databases;
2.索引一个文档(保存)
ElasticSearch:保存一个数据,保存在哪个索引的哪个类型下,指定用哪个唯一标识。
MySQL:保存一个数据,保存在哪个数据表的哪个数据库里面。
1)插入数据
PUT customer/external/1
{ "name": "John Doe" } ## 发送的数据
- _代表元数据
- _index表示在那个索引下
- _type表示在那个类型下
- _id表示唯一索引
- _version表示数据的版本,会通过修改次数逐步叠加
- result表示创建时的状态,created表示第一次创建,之后修改就是updated
- shards表示分片
2)在 customer 索引下的 external 类型下保存 1 号数据,1代表的是唯一标识。
3)put和post区别
- post新增修改二合一,不带id就是新增,带id就是更新。put必须携带id
- POST 新增。如果不指定 id,会自动生成 id。指定 id 就会修改这个数据,并新增版本号 PUT 可以新增可以修改。
- PUT 必须指定 id;由于 PUT 需要指定 id,我们一般都用来做修改 操作,不指定 id 会报错。
3.查询文档
GET 127.0.0.1:9200/customer/external/1
结果:
{
"_index": "customer", //在哪个索引
"_type": "external", //在哪个类型
"_id": "1", //记录 id
"_version": 2, //版本号
"_seq_no": 1, //并发控制字段,每次更新就会+1,用来做乐观锁
"_primary_term": 1, //同上,主分片重新分配,如重启,就会变化
"found": true,
"_source": { //真正的内容
"name": "John Doe"
}
}
当程序中可能出现并发的情况时,就需要保证在并发情况下数据的准确性,以此确保当前用户和其他用户一起操作时,所得到的结果和他单独操作时的结果是一样的。这就叫做并发控制。并发控制的目的是保证一个用户的工作不会对另一个用户的工作产生不合理的影响。没有做好并发控制,就可能导致脏读、幻读和不可重复读等问题。
1)更新携带 ?if_seq_no=0&if_primary_term=1
- _seq_no:用来控制并发,当修改以后,_seq_no就会变化
- 想要修改,必须首先拿到最新数据,其次传递最新的_seq_no值
2)乐观锁和悲观锁
乐观锁:在关系数据库管理系统里,乐观并发控制(又名“乐观锁”,Optimistic Concurrency Control,缩写“OCC”)是一种并发控制的方法。它假设多用户并发的事务在处理时不会彼此互相影响,各事务能够在不产生锁的情况下处理各自影响的那部分数据。在提交数据更新之前,每个事务会先检查在该事务读取数据后,有没有其他事务又修改了该数据。如果其他事务有更新的话,正在提交的事务会进行回滚。
悲观锁:悲观锁(Pessimistic Lock),指在应用程序中显示地为数据资源加锁。悲观锁,顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。悲观锁假定当前事务操纵数据资源时,肯定还有其他事务同时访问该数据资源,为了避免当前事务的操作受到干扰,先锁定资源。
4.更新文档
1)方式一
POST 127.0.0.1:9200/customer/external/1/_update
{
"doc":{
"name":"John Doew"
}
}
结论:
1.如果携带_update,参数中一定要添加”doc”。
2.加_update会对比源数据,与原来一样,则什么都不处理,文档 version 不增加。
2)方式二
POST 127.0.0.1:9200/customer/external/1/
{
"name":"John Doe2"
}
3)方式三
PUT 127.0.0.1:9200/customer/external/1/
{
"name":"John Doe2"
}
结论:
1.不会检查源数据
2.PUT 操作总会将数据重新保存并增加 version 版本
4)方式四——更新同时增加属性
POST 127.0.0.1:9200/customer/external/1/_update
{
"doc":{
"name":"John Doew"
"age":"J20"
}
}
PUT和POST不带_update也可以
5.删除文档
DELETE 127.0.0.1:9200/customer/external/1
DELETE 127.0.0.1:9200/customer
- 可以通过唯一标识删除数据
- 也可以直接删除掉索引
- elasticsearch没有提供直接删除文档的方法
6.bulk批量API
POST 127.0.0.1:9200/customer/external/_bulk
{"index":{"_id":"1"}}
{"name": "John Doe" }
{"index":{"_id":"2"}}
{"name": "Jane Doe" }
语法格式:
{ action: { metadata }}\n
{ request body }\n
{ action: { metadata }}\n
{ request body }\n
复杂实例:
POST /_bulk
{ "delete": { "_index": "website", "_type": "blog", "_id": "123"}}
{ "create": { "_index": "website", "_type": "blog", "_id": "123"}}
{ "title": "My first blog post"}
{ "index": { "_index": "website", "_type": "blog"}}
{ "title": "My second blog post"}
{ "update": { "_index": "website", "_type": "blog", "_id": "123", "_retry_on_conflict" : 3}}
{ "doc" : {"title" : "My updated blog post"}}
bulk API 以此按顺序执行所有的 action(动作)。如果一个单个的动作因任何原因而失败, 它将继续处理它后面剩余的动作。当 bulk API 返回时,它将提供每个动作的状态(与发送 的顺序相同),所以您可以检查是否一个指定的动作是不是失败了。
7.样本测试数据
导入测试数据 POST bank/account/_bulk
https://gitee.com/xlh_blog/common_content/blob/master/es%E6%B5%8B%E8%AF%95%E6%95%B0%E6%8D%AE.json
二:进阶检索
1.SearchAPI
ES 支持两种基本方式检索 :
- 一个是通过使用 REST request URI 发送搜索参数(uri+检索参数)
- 另一个是通过使用 REST request body 来发送它们(uri+请求体)
1)一切检索从_search 开始
- GET
bank/_search
检索 bank 下所有信息,包括 type 和 docs - GET
bank/_search?q=*&sort=account_number:asc
请求参数方式检索
响应结果解释:
took - Elasticsearch 执行搜索的时间(毫秒)
time_out - 告诉我们搜索是否超时
_shards - 告诉我们多少个分片被搜索了,以及统计了成功/失败的搜索分片
hits - 搜索结果
hits.total - 搜索结果
hits.hits - 实际的搜索结果数组(默认为前 10 的文档)
sort - 结果的排序 key(键)(没有则按 score 排序)
score 和 max_score –相关性得分和最高得分(全文检索用)
2)uri+请求体进行检索
GET bank/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"account_number": {
"order": "desc"
}
}
]
}
HTTP 客户端工具(POSTMAN),get 请求不能携带请求体,我们变为 post 也是一样的 我们 POST 一个 JSON 风格的查询请求体到 _search API。 需要了解,一旦搜索的结果被返回,Elasticsearch 就完成了这次请求,并且不会维护任何 服务端的资源或者结果的 cursor(游标)
2.Query DSL
1)基本语法格式
Elasticsearch 提供了一个可以执行查询的 Json 风格的 DSL(domain-specific language 领域特 定语言)。这个被称为 Query DSL。该查询语言非常全面,并且刚开始的时候感觉有点复杂, 真正学好它的方法是从一些基础的示例开始的。
- 一个查询语句 的典型结构
{
QUERY_NAME: {
ARGUMENT: VALUE,
ARGUMENT: VALUE,...
}
}
- 如果是针对某个字段,那么它的结构如下:
{
QUERY_NAME: {
FIELD_NAME: {
ARGUMENT: VALUE,
ARGUMENT: VALUE,...
}
}
}
例:GET bank/_search
{
"query": {
"match_all": {}
},
"from": 0,
"size": 5,
"sort": [
{
"account_number": {
"order": "desc"
}
}
]
}
- query 定义如何查询,
- match_all 查询类型【代表查询所有的所有】,es 中可以在 query 中组合非常多的查 询类型完成复杂查询
- 除了 query 参数之外,我们也可以传递其它的参数以改变查询结果。如 sort,size
- from+size 限定,完成分页功能
- sort 排序,多字段排序,会在前序字段相等时后续字段内部排序,否则以前序为准
2)返回部分字段
GET bank/_search
{
"query": {
"match_all": {}
},
"from": 0,
"size": 5,
"_source": ["age","balance"]
}
3)match【匹配查询】
1.基本类型(非字符串),精确匹配
GET bank/_search
{
"query": {
"match": {
"account_number": "20"
}
}
}
- match 返回 account_number=20 的
2.字符串,全文检索
GET bank/_search
{
"query": {
"match": {
"address": "mill"
}
}
}
- 最终查询出 address 中包含 mill 单词的所有记录
- match 当搜索字符串类型的时候,会进行全文检索,并且每条记录有相关性得分。
3.字符串,多个单词(分词+全文检索)
GET bank/_search
{
"query": {
"match": {
"address": "mill road"
}
}
}
- 最终查询出 address 中包含 mill 或者 road 或者 mill road 的所有记录,并给出相关性得分
4)match_phrase【短语匹配】
将需要匹配的值当成一个整体单词(不分词)进行检索
GET bank/_search
{
"query": {
"match_phrase": {
"address": "mill road"
}
}
}
- 查出 address 中包含 mill road 的所有记录,并给出相关性得分
- match_phrase与address .keyword的区别就是,match_phrase只要包含就能查出来,属于模糊匹配。address .keyword属于精确匹配。
5)multi_match【多字段匹配】
GET bank/_search
{
"query": {
"multi_match": {
"query": "mill",
"fields": ["state","address"]
}
}
}
- state 或者 address 包含 mill
6)bool【复合查询】
bool 用来做复合查询: 复合语句可以合并任何 其它查询语句,包括复合语句,了解这一点是很重要的。这就意味 着,复合语句之间可以互相嵌套,可以表达非常复杂的逻辑。
1.must:必须达到 must 列举的所有条件
GET bank/_search
{
"query": {
"bool": {
"must": [
{"match": {"address": "mill"}},
{"match": {"gender": "M"}}
]
}
}
}
2.should:应该达到 should 列举的条件,如果达到会增加相关文档的评分,并不会改变 查询的结果。如果 query 中只有 should 且只有一种匹配规则,那么 should 的条件就会 被作为默认匹配条件而去改变查询结果
GET bank/_search
{
"query": {
"bool": {
"must": [
{"match": {"address": "mill"}},
{"match": {"gender": "M"}}
],
"should": [
{"match": { "address": "lane" }}
]
}
}
}
3.must_not 必须不是指定的情况
GET bank/_search
{
"query": {
"bool": {
"must": [
{"match": {"address": "mill"}},
{"match": {"gender": "M"}}
],
"should": [
{"match": { "address": "lane" }}
],
"must_not": [
{"match": { "email": "baluba.com" }}
]
}
}
}
- address 包含 mill,并且 gender 是 M,如果 address 里面有 lane 最好不过,但是 email 必 须不包含 baluba.com
7)filter【结果过滤】
并不是所有的查询都需要产生分数,特别是那些仅用于 “filtering”(过滤)的文档。为了不 计算分数 Elasticsearch 会自动检查场景并且优化查询的执行。
GET bank/_search
{
"query": {
"bool": {
"must": [
{"match": {"address": "mill"}},
{"match": {"gender": "M"}}
],
"filter": {
"range": {
"balance": {
"gte": 10000,
"lte": 20000
}
}
}
}
}
}
8)term
和 match 一样。匹配某个属性的值。全文检索字段用 match,其他非 text 字段匹配用 term。
GET bank/_search
{
"query": {
"bool": {
"must": [
{"term": {"age": {"value": "28"}}},
{"match": {"address": "990 Mill Road"}}
]
}
}
}
9)aggregations(执行聚合)
聚合提供了从数据中分组和提取数据的能力。最简单的聚合方法大致等于 SQL GROUP BY 和 SQL 聚合函数。在 Elasticsearch 中,您有执行搜索返回 hits(命中结果),并且同时返 回聚合结果,把一个响应中的所有 hits(命中结果)分隔开的能力。这是非常强大且有效的, 您可以执行查询和多个聚合,并且在一次使用中得到各自的(任何一个的)返回结果,使用 一次简洁和简化的 API 来避免网络往返。
1.搜索 address 中包含 mill 的所有人的年龄分布以及平均年龄,但不显示这些人的详情。
GET bank/_search
{
"query":{
"match":{
"address":"mill"
}
},
"aggs":{
"group_by_state":{
"terms":{
"field":"age"
}
},
"avg_age":{
"avg":{
"field":"age"
}
}
},
"size":0
}
解释:
1.size:0 不显示搜索数据
2.aggs:执行聚合。聚合语法如下
3."aggs": {
"aggs_name 这次聚合的名字,方便展示在结果集中": {
"AGG_TYPE 聚合的类型(avg,term,terms)": {} }
},
2.按照年龄聚合,并且请求这些年龄段的这些人的平均薪资
GET bank/account/_search
{
"query":{
"match_all":{
}
},
"aggs":{
"age_avg":{
"terms":{
"field":"age",
"size":1000
},
"aggs":{
"banlances_avg":{
"avg":{
"field":"balance"
}
}
}
}
},
"size":1000
}
3.查出所有年龄分布,并且这些年龄段中 M 的平均薪资和 F 的平均薪资以及这个年龄 段的总体平均薪资
GET bank/account/_search
{
"query":{
"match_all":{
}
},
"aggs":{
"age_agg":{
"terms":{
"field":"age",
"size":100
},
"aggs":{
"gender_agg":{
"terms":{
"field":"gender.keyword",
"size":100
},
"aggs":{
"balance_avg":{
"avg":{
"field":"balance"
}
}
}
},
"balance_avg":{
"avg":{
"field":"balance"
}
}
}
}
},
"size":1000
}
3.Mapping
1)字段类型
2)映射
Mapping 是用来定义一个文档(document),以及它所包含的属性(field)是如何存储和 索引的。相当于mysql的设计表,查看字段类型
比如,使用 mapping 来定义:
- 哪些字符串属性应该被看做全文本属性(full text fields)。
- 哪些属性包含数字,日期或者地理位置。
- 文档中的所有属性是否都能被索引(_all 配置)。
- 日期的格式。
- 自定义映射规则来执行动态添加属性。
查看 mapping 信息:
GET bank/_mapping
修改 mapping 信息:
https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html
3)新版本改变
Es7 及以上移除了 type 的概念。
关系型数据库中两个数据表示是独立的,即使他们里面有相同名称的列也不影响使用, 但 ES 中不是这样的。elasticsearch 是基于 Lucene 开发的搜索引擎,而 ES 中不同 type 下名称相同的 filed 最终在 Lucene 中的处理方式是一样的。
- 两个不同 type 下的两个 user_name,在 ES 同一个索引下其实被认为是同一个 filed, 你必须在两个不同的 type 中定义相同的 filed 映射。否则,不同 type 中的相同字段 名称就会在处理中出现冲突的情况,导致 Lucene 处理效率下降。
- 去掉 type 就是为了提高 ES 处理数据的效率。
Elasticsearch 7.x
- URL 中的 type 参数为可选。比如,索引一个文档不再要求提供文档类型。
Elasticsearch 8.x
- 不再支持 URL 中的 type 参数。
解决:
- 将索引从多类型迁移到单类型,每种类型文档一个独立索引
- 将已存在的索引下的类型数据,全部迁移到指定位置即可。详见数据迁移
4)创建映射
PUT /my_index
{
"mappings": {
"properties": {
"age":{"type": "integer"},
"email":{"type": "keyword"},
"name":{"type":"text"}
}
}
}
5)添加新的映射
PUT /my_index/_mapping
{
"properties": {
"employee-id":{
"type":"keyword",
"index":false
}
}
}
- “index”:false表示该字段不需要被索引,不会被检索到。此时不能用employee-id进行检索。
- index默认都是true
6)更新映射
对于已经存在的映射字段,我们不能更新。更新必须创建新的索引进行数据迁移
7)数据迁移
先创建出 new_twitter 的正确映射。然后使用如下方式进行数据迁移
POST _reindex
[固定写法]
{
"source": {
"index": "bank",
"type": "account"
},
"dest": {
"index": "newbank"
}
}
GET /newbank/_search
- 不用type,老的数据迁移过来
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/84117.html