elasticsearch

elasticsearch是一个近实时分布式搜索和分析引擎,它用于全文搜索、结构化搜索、分析以及将这三者混合使用,使用java编写,基于Lucene 实现

优势

  1. 分布式的实时文件存储,每个字段都被索引并可被搜索
  2. 实时分析的分布式搜索引擎
  3. 横向可扩展:支持上百台服务节点的扩展,集群增加机器简单,支持处理PB级数据
  4. 分片机制:
    允许水平分割扩展数据,允许分片和并行操作从而提高性能和吞吐量
    提供高性能:同一个索引可以分多个主分片(primary shard),每个主分片拥有自己的副本分片(replica shard),每个副本分片都可以提供服务,提升系统搜索请求的吞吐量和性能
    提供高可用性:同一个索引可以分多个主分片,每个主分片拥有零个或者多个副本,如果主分片挂了,可以从副本分片中选择一个作为主分片继续提供服务
  5. 隐藏复杂实现:Elasticsearch 内部隐藏了分布式系统的复杂性,我们不用去关心它是如何做到高可用,可扩展,高性能的
  6. 易用开源:不需要额外配置,就可以运行一个Elasticsearch服务,开源

基本概念

  1. Cluster:集群
    一个集群包含多个节点,对外提供服务,每个节点属于哪个集群通过配置文件中的集群名称决定
  2. Node:节点
    集群中的一个节点,每个节点也有一个名称,默认是随机分配,也可以自己指定,在es集群中通过节点名称进行管理和通信
  3. Index:索引
    索引是具有相同结构的文档集合,作用相当于mysql中的库
  4. Type:类型
    一个索引可以对应一个或者多个类型,类型可以当做是索引的逻辑分区,作用相当于mysql中的表
  5. Document:文档
    存储在es中的一个JSON格式的字符串,每一个文档有一个文档ID,如果没有自己指定ID,系统会自动生成一个ID,文档的index/type/id必须是唯一的,作用相当于mysql中的行
  6. field:字段
    一个文档会包含多个字段,每个字段都对应一个字段类型,类似于mysql中的列
  7. shard:分片
    es中分为primary shard主分片和replica shard副本分片
    主分片:当存一个文档的时候会先存储在主分片中,然后复制到不同的副本分片中,默认一个索引会有5个主分片,当然可以自己指定分片数量,当分片一旦建立,分片数量不能改变
    副本分片:每一个主分片会有零个或者多个副本,副本主要是主分片的复制,通过副本分片可以提供高可用性,当一个主分片挂了,可以从副本分片中选择一个作为主分片,还可以提高性能,所以主分片不能和副本分片部署在相同的节点上
  8. replica:复制
    复制是为了防止单点问题,可以做到对故障进行转移,保证系统的高可用
  9. 映射
    描述数据在每个字段内如何存储,是定义存储和索引的文档类型及字段的过程,索引中的每一个文档都有一个类型,每种类型都有它自己的映射,一个映射定义了文档结构内每个字段的数据类型
    使用GET /index/_mapping/type获取对应的/index/type的映射信息

基本操作

建议安装Elasticsearch+Kibana,在Kibana的操作界面对es进行操作

Elasticsearch提供了RESTful接口可以对Elasticsearch进行操作

Kibana操作页面

在Kibana的Dev Tools界面可以对es进行操作,在console界面敲命令,点执行,会在右面输出结果



验证Elasticsearch是否安装成功

http://localhost:9200/?pretty

{
  "name" : "UzOujcc", //节点名称
  "cluster_name" : "mx", //集群名称,我自己设置的
  "cluster_uuid" : "d2K1M95DRzG9XOPDOR_DEQ",
  "version" : {
    "number" : "6.2.4", //集群版本
    "build_hash" : "ccec39f",
    "build_date" : "2018-04-12T20:37:28.497551Z",
    "build_snapshot" : false,
    "lucene_version" : "7.2.1",
    "minimum_wire_compatibility_version" : "5.6.0",
    "minimum_index_compatibility_version" : "5.0.0"
  },
  "tagline" : "You Know, for Search"
}
复制代码

es提供了一套api,叫做cat api,可以查看es中的信息数据

查看集群健康状况

命令:GET /_cat/health?v



status代表着集群的健康程度

  1. green:每个索引的primary shard和replica shard都是active状态的
  2. yellow:每个索引的primary shard都是active状态的,但是部分replica shard不是active状态,处于不可用的状态
  3. red:不是所有索引的primary shard都是active状态的,部分索引有数据丢失了
索引操作

查看索引信息

命令:GET _cat/indices?v



有五个索引,都是的测试数据

新建索引

命令:PUT /myindex

{
  "acknowledged": true,
  "shards_acknowledged": true,
  "index": "myindex"
}
复制代码

删除索引

命令:DELETE myindex

{
  "acknowledged": true
}
复制代码
文档操作

添加文档

添加文档是向索引中添加一条文档,让其能够搜索,文档格式是json串,如果es中有相同id的文档存在则更新这个文档

当创建文档的时候,如果索引不存在,则会自动创建该索引,而且es默认会对document每个field都建立倒排索引,让其可以被搜索

命令:

PUT /index/type/id 
{ 
	"json数据结构体 "
}
复制代码

例:

PUT /school/student/1
{
  "name":"张三",
  "age":21,
  "class":2,
  "gender":"男"
}
复制代码

返回:

{
  "_index": "school", //索引
  "_type": "student", //类型
  "_id": "1", //id,如果不指定则会系统生成一个20位的id,文档被分到那个分片上就是根据id的散劣值进行控制
  "_version": 1, //文档版本号,通过这个进行并发控制
  "result": "created", //操作类型
  "_shards": { //分片信息
    "total": 2, //文档被创建时在多少个分片进行了操作(包括主分片和副本分片)
    "successful": 1, //添加成功的索引分片数量
    "failed": 0 //失败的索引分片数量
  },
  "_seq_no": 0,
  "_primary_term": 1
}
复制代码

修改文档

方式1:使用put方式更新文档

PUT /school/student/1
{
  "name":"吕布",
  "age":21,
  "class":2,
  "gender":"男"
}
复制代码

返回:

{
  "_index": "school",
  "_type": "student",
  "_id": "1",
  "_version": 2, //版本号+1
  "result": "updated", // 修改
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 1,
  "_primary_term": 1
}
复制代码

这种方式替换需要带上所有的field,才能进行信息的修改,操作类似于覆盖

方式2:post更新文档

POST /school/student/1/_update
{
  "doc": {
    "name":"吕布1"
  }
}
复制代码

使用post更新文档,可以只更新部分字段

查询文档

查询单条文档

命令:GET /school/student/1

返回:

{
  "_index": "school",
  "_type": "student",
  "_id": "1",
  "_version": 3,
  "found": true,
  "_source": {
    "name": "吕布1",
    "age": 21,
    "class": 2,
    "gender": "男"
  }
}
复制代码

删除文档

命令:DELETE school/student/1

返回:

{
  "_index": "school",
  "_type": "student",
  "_id": "1",
  "_version": 4,
  "result": "deleted", //删除
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 3,
  "_primary_term": 1
}
复制代码

这时在查询就会显示"found": false

映射与分析

Elasticsearch 中的数据可以概括的分为两类:精确值和全文

  1. 精确值:精确值是确定的值,比如用户ID,字符串也可以表示精确值,例如用户名或邮箱地址。对于精确值来讲,Foofoo 是不同的,精确值的查询简单,要么匹配查询,要么不匹配
  2. 全文:全文是指文本数据(通常以人类容易识别的语言书写),例如一个推文的内容或一封邮件的内容,全文的查询较为复杂,他需要的是匹配查询的程度有多大

在es中使用 倒排索引来进行快速的全文搜索。一个倒排索引由文档中所有不重复词的列表构成,对于其中每个词,有一个包含它的文档列表,倒排索引具体内容请戳:www.elastic.co/guide/cn/el…

映射

es中的映射(mapping)用来描述数据在每个字段内如何存储,是定义存储和索引的文档类型及字段的过程,索引中的每一个文档都有一个类型,每种类型都有它自己的映射,一个映射定义了文档结构内每个字段的数据类型,作用相当于mysql中的DDL语句

查询索引类型的映射

GET /ad/_mapping/phone

{
  "school": {
    "mappings": {
      "student": {
        "properties": {
          "age": {
            "type": "long"
          },
          "class": {
            "type": "long"
          },
          "gender": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "name": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          }
        }
      }
    }
  }
}
复制代码

动态映射

动态映射不需要事先定义映射,文档在写入es的时候,会根据文档字段自动识别类型

映射规则:

Json 数据类型

es 数据类型

null

没有字段添加

true,false

boolean

Integer

long

object

object

array

依赖于数组中首个非空值

string

text和keyword

日期

date或text

静态映射

静态映射需要事先定义好映射,包含文档的各个字段及其类型

PUT books
{
  "mappings": {
    "book":{
      "properties": {
        "id":{"type": "long"},
        "bookName":{"type": "text"},
        "ad":{"type": "text"}
      }
    }
  }
}
复制代码

es中的字符串类型分为keywordtext

  1. keyword:用于索引结构化内容的字段,例如电子邮件地址,主机名,状态代码,邮政编码或标签。它们通常用于过滤,排序,和聚合。keyword字段只能按其确切值进行搜索。如果您需要索引电子邮件正文或产品说明等全文内容,则可能应该使用text字段
  2. text:用于索引全文值的字段,例如电子邮件正文或产品说明。这些字段是analyzed,它们通过分词器传递 ,以在被索引之前将字符串转换为单个术语的列表。分析过程允许Elasticsearch搜索单个单词中 每个完整的文本字段。文本字段不用于排序,很少用于聚合

有时候一个字段同时拥有全文类型(text)和关键字类型(keyword)是有用的:一个用于全文搜索,另一个用于聚合和排序。这可以通过多字段类型来实现(动态映射是字符串的默认映射类型)

多种查询
url参数搜索

这种方式就是类似于get请求,将请求参数拼接到链接上,例GET /school/student/_search?参数,多个参数用&分开

查询所有

命令:GET /school/student/_search

返回:

{
  "took": 7, //查询耗时,毫秒
  "timed_out": false, //是否超时,timeout 不是停止执行查询,它仅仅是告知正在协调的节点返回到目前为止收集的结果并且关闭连接
  "_shards": {
    "total": 5, //请求的分片数量,索引拆成了5个分片,所以对于搜索请求,会打到所有的primary shard
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 2, //符合条件的总条数,这里查的是所有
    "max_score": 1, //匹配分数
    "hits": [ //数据
      {
        "_index": "school",
        "_type": "student",
        "_id": "2",
        "_score": 1,
        "_source": {
          "name": "houyi",
          "age": 23,
          "class": 2,
          "gender": "男"
        }
      },
      {
        "_index": "school",
        "_type": "student",
        "_id": "1",
        "_score": 1,
        "_source": {
          "name": "吕布",
          "age": 21,
          "class": 2,
          "gender": "男"
        }
      }
    ]
  }
}
复制代码

多索引,多type搜索

在URL中指定特殊的索引和类型进行多索引,多type搜索

  1. /_search:在所有的索引中搜索所有的类型
  2. /school/_search:在 school 索引中搜索所有的类型
  3. /school,ad/_search:在 schoolad索引中搜索所有的类型
  4. /s*,a*/_search:在所有以ga开头的索引中所有所有的类型
  5. /school/student/_search:在school索引中搜索student类型
  6. /school,ad/student,phone/_search:在schoolad索引上搜索studentphone类型
  7. /_all/student,phone/_search:在所有的索引中搜索studentphone类型

按条件查询

命令:GET /school/student/_search?q=name:houyi

查询name是houyi的记录

更多搜索参数:



查询DSL

elasticsearch提供了基于JSON的完整查询DSL来定义查询,DSL拥有一套查询组件,这些组件可以以无限组合的方式进行搭配,构建各种复杂的查询

  1. 叶子语句:就像match语句,被用于将查询的字符串与一个字段或多个字段进行对比(单个条件)
    比如:
GET /ad/phone/_search
{
  "query": {
    "match": {
      "name": "phone"
    }
  }
}
复制代码
  1. 复合查询:用户合并其他查询语句,比如一个bool语句,允许你在需要的时候组合其他语句,包括mustmust_notshouldfilter语句(多条件组合查询)
    比如:
GET /ad/phone/_search
{
  "query": {
    "bool": {
      "must": [
        {"match": {
          "name": "phone"
        }}
      ]
      , "must_not": [
        {"match": {
          "color": "red"
        }}
      ]
      , "should": [
        {"match": {
          "price": 5000
        }}
      ]
      , "filter": {
          "term": {
            "label": "phone"
          }
      }
    }
  }
}
复制代码

must:表示文档一定要包含查询的内容

must_not:表示文档一定不要包含查询的内容

should:表示如果文档匹配上可以增加文档相关性得分

事实上我们可以使用两种结构化语句: 结构化查询query DSL和结构化过滤Filter DSL

  1. 结构化查询query DSL用于检查内容与条件是否匹配,内容查询中使用的bool和match字句,用于计算每个文档的匹配得分,元字段_score表示匹配度,查询的结构中以query参数开始来执行内容查询
  2. 结构化过滤Filter DSL只是简单的决定文档是否匹配,内容过滤中使用的term和range字句,会过滤 调不匹配的文档,并且不影响计算文档匹配得分
    使用过滤查询会被es自动缓存用来提高效率

原则上来说,使用查询语句做全文本搜索或其他需要进行相关性评分的时候,剩下的全部用过滤语句

新建一个稍微复杂的索引,添加三条文档

PUT /ad/phone/1
{
  "name":"phone 8",
  "price": 6000,
  "color":"white",
  "ad":"this is a white phone",
  "label":["white","nice"]
}

PUT /ad/phone/2
{
  "name":"xiaomi 8",
  "price": 4000,
  "color":"red",
  "ad":"this is a red phone",
  "label":["white","xiaomi"]
}

PUT /ad/phone/3
{
  "name":"huawei p30",
  "price": 5000,
  "color":"white",
  "ad":"this is a white phone",
  "label":["white","huawei"]
}

复制代码

查询示例:

  1. 获取所有
GET /ad/phone/_search
{
  "query": {
    "match_all": {}
  }
}
复制代码

match_all匹配所有数据,返回的结果中元字段_score得分为1

  1. 分页查询,从第二条开始,查两条(不要使用fromsize进行深度分页,会有性能问题)
GET /ad/phone/_search
{
  "query": {
    "match_all": {}
  },
  "from": 1,
  "size": 2
}
复制代码

这种分页方式如果进行深度分页,比如到100页,每页十条数据,它会从每个分片都查询出100*10条数据,假设有五个分片,就是5000条数据,然后在内存中进行排序,然后返回拍过序之后的集合中的第1000-1010条数据

  1. 指定查询出来的数据返回的字段
GET /ad/phone/_search
{
  "query": {
    "match_all": {}
  },
  "_source": ["name","price"]
}
复制代码

返回的数据中只返回nameprice字段

  1. ad字段中包含单词white
GET /ad/phone/_search
{
  "query": {
    "match": {
      "ad": "white"
    }
  }
}
复制代码

返回的结果中元字段_score有评分,说明使用query会计算评分

  1. ad字段中包含单词white,并按照价格升序排列
GET /ad/phone/_search
{
  "query": {
    "match": {
      "ad": "white"
    }
  }, 
  "sort": [
    {
      "price": {
        "order": "asc"
      }
    }
  ]
}
复制代码
  1. 价格字段大于5000
GET /ad/phone/_search
{
  "query": {
    "bool": {
      "filter": {
        "range": {
          "price": {
            "gt": 5000
          }
        }
      }
    }
  }
}
复制代码

返回的结果中元字段_score字段等于0,没评分,说明使用filter不会计算评分

  1. ad字段中包含单词white,价格字段大于5000
GET /ad/phone/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "ad": "white"
          }
        }
      ], 
      "filter": {
        "range": {
          "price": {
            "gt": 5000
          }
        }
      }
    }
  }
}
复制代码
  1. 查询name字段包含单词phone的文档的数量
GET /ad/phone/_count
{
  "query": {
    "match": {
      "name": "phone"
    }
  }
}
复制代码

搜索示例

  1. match_all查询
    查询简单的匹配所有文档
GET /ad/phone/_search
{
  "query": {
    "match_all": {}
  }
}
复制代码
  1. match查询
    支持全文搜索和精确查询,取决于字段是否支持全文检索
    全文检索:
GET /ad/phone/_search
{
  "query": {
    "match": {
      "ad": "a red"
    }
  }
}
复制代码

全文检索会将查询的字符串先进行分词,a red会分成为ared,然后在倒排索引中进行匹配,所以这条语句会将三条文档都查出来

精确查询:

GET /ad/phone/_search
{
  "query": {
    "match": {
      "price": "6000"
    }
  }
}
复制代码

对于精确值的查询,可以使用 filter 语句来取代 query,因为 filter 将会被缓存

operator操作:

match 查询还可以接受 operator 操作符作为输入参数,默认情况下该操作符是 or 。我们可以将它修改成 and 让所有指定词项都必须匹配

GET /ad/phone/_search
{
  "query": {
    "match": {
      "ad": {
        "query": "a red",
        "operator": "and"
      }
    }
  }
}
复制代码

精确度匹配:

match 查询支持 minimum_should_match 最小匹配参数, 可以指定必须匹配的词项数用来表示一个文档是否相关。我们可以将其设置为某个具体数字(指需要匹配倒排索引的词的数量),更常用的做法是将其设置为一个百分数,因为我们无法控制用户搜索时输入的单词数量

GET /ad/phone/_search
{
  "query": {
    "match": {
      "ad": {
        "query": "a red",
        "minimum_should_match": "2"
      }
    }
  }
}
复制代码

只会返回匹配上ared两个词的文档返回,如果minimum_should_match是1,则只要匹配上其中一个词,文档就会返回

  1. multi_match查询
    多字段查询,比如查询colorad字段包含单词red的文档
GET /ad/phone/_search
{
  "query": {
    "multi_match": {
      "query": "red",
      "fields": ["color","ad"]
    }
  }
}
复制代码
  1. range查询
    范围查询,查询价格大于4000小于6000的文档
GET /ad/phone/_search
{
  "query": {
    "range": {
      "price": {
        "gt": 4000,
        "lt": 6000
      }
    }
  }
}
复制代码

范围查询操作符:gt (大于),gte(大于等于),lt(小于),lte(小于等于);

  1. term查询
    精确值查询
    查询price字段等于6000的文档
GET /ad/phone/_search
{
  "query": {
    "term": {
      "price": {
        "value": "6000"
      }
    }
  }
}
复制代码

查询name字段等于phone 8的文档

GET /ad/phone/_search
{
  "query": {
    "term": {
      "name": {
        "value": "phone 8"
      }
    }
  }
}
复制代码

返回值如下,没有查询到名称为phone 8的文档

{
  "took": 5,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 0,
    "max_score": null,
    "hits": []
  }
}
复制代码

为什么没有查到phone 8的这个文档那,这里需要介绍一下term的查询原理

term查询会去倒排索引中寻找确切的term,它并不会走分词器,只会去配倒排索引 ,而name字段的type类型是text,会进行分词,将phone 8 分为phone8,我们使用term查询phone 8时倒排索引中没有phone 8,所以没有查询到匹配的文档

term查询与match查询的区别

  • term查询时,不会分词,直接匹配倒排索引
  • match查询时会进行分词,查询phone 8时,会先分词成phone8,然后去匹配倒排索引,所以结果会将phone 8xiaomi 8两个文档都查出来

还有一点需要注意,因为term查询不会走分词器,但是回去匹配倒排索引,所以查询的结构就跟分词器如何分词有关系,比如新增一个/ad/phone类型下的文档,name字段赋值为Oppo,这时使用term查询Oppo不会查询出文档,这时因为es默认是用的standard分词器,它在分词后会将单词转成小写输出,所以使用oppo查不出文档,使用小写oppo可以查出来

GET /ad/phone/_search
{
  "query": {
    "term": {
      "name": {
        "value": "Oppo" //改成oppo可以查出新添加的文档
      }
    }
  }
}
复制代码

这里说的并不是想让你了解standard分词器,而是要get到所有像term这类的查询结果跟选择的分词器有关系,了解选择的分词器分词方式有助于我们编写查询语句

  1. terms查询
    terms查询与term查询一样,但它允许你指定多直进行匹配,如果这个字段包含了指定值中的任何一个值,那么这个文档满足条件
GET /ad/phone/_search
{
  "query": {
    "terms": {
      "ad": ["red","blue"]
    }
  }
}
复制代码
  1. exists 查询和 missing 查询
    用于查找那些指定字段中有值 (exists) 或无值 (missing) 的文档
    指定name字段有值:
GET /ad/phone/_search
{
  "query": {
    "bool": {
      "filter": {
        "exists": {
          "field": "name"
        }
      }
    }
  }
}
复制代码

指定name字段无值:

GET /ad/phone/_search
{
  "query": {
    "bool": {
      "filter": {
        "missing": {
          "field": "name"
        }
      }
    }
  }
}
复制代码
  1. match_phrase查询
    短语查询,精确匹配,查询a red会匹配ad字段包含a red短语的,而不会进行分词查询,也不会查询出包含a 其他词 red这样的文档
GET /ad/phone/_search
{
  "query": {
    "match_phrase": {
      "ad": "a red"
    }
  }
}
复制代码
  1. scroll查询
    类似于分页查询,不支持跳页查询,只能一页一页往下查询,scroll查询不是针对实时用户请求,而是针对处理大量数据,例如为了将一个索引的内容重新索引到具有不同配置的新索引中
POST /ad/phone/_search?scroll=1m
{
  "query": {
    "match_all": {}
  },
  "size": 1,
  "from": 0
}
复制代码

返回值包含一个 "_scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAAAQFlV6T3VqY2NaVDBLRG5uZXdiZ0hFYUEAAAAAAAAAERZVek91amNjWlQwS0RubmV3YmdIRWFBAAAAAAAAABIWVXpPdWpjY1pUMEtEbm5ld2JnSEVhQQAAAAAAAAATFlV6T3VqY2NaVDBLRG5uZXdiZ0hFYUEAAAAAAAAAFBZVek91amNjWlQwS0RubmV3YmdIRWFB"

下次查询的时候使用_scroll_id就可以查询下一页的文档

POST /_search/scroll 
{
    "scroll" : "1m", 
    "scroll_id" : "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAAAYFlV6T3VqY2NaVDBLRG5uZXdiZ0hFYUEAAAAAAAAAGRZVek91amNjWlQwS0RubmV3YmdIRWFBAAAAAAAAABYWVXpPdWpjY1pUMEtEbm5ld2JnSEVhQQAAAAAAAAAXFlV6T3VqY2NaVDBLRG5uZXdiZ0hFYUEAAAAAAAAAFRZVek91amNjWlQwS0RubmV3YmdIRWFB" 
}
复制代码
  1. multi get查询
    允许基于索引,类型(可选)和id(以及可能的路由)获取多个文档,如果某个文档获取失败则将错误信息包含在响应中
GET /ad/phone/_mget
{
  "ids": ["1","8"]
}
复制代码
  1. bulk批量操作
    bulk批量操作可以在单次API调用中实现多个文档的createindexupdatedelete。这可以大大提高索引速度
    bulk请求体如下
{ action: { metadata }}\n 
{ request body        }\n
{ action: { metadata }}\n
{ request body        }\n
...
复制代码

行为(action)必须是以下几种:

行为

解释

create

当文档不存在时创建之。详见《创建文档》

index

创建新文档或替换已有文档。见《索引文档》和《更新文档》

update

局部更新文档。见《局部更新》

delete

删除一个文档。见《删除文档》

在索引、创建、更新或删除时必须指定文档的_index_type_id这些元数据(metadata)

例:

PUT _bulk
{ "create" : { "_index" : "ad", "_type" : "phone", "_id" : "6" }}
{ "doc" : {"name" : "bulk"}}
{ "index" : { "_index" : "ad", "_type" : "phone", "_id" : "6" }}
{ "doc" : {"name" : "bulk"}}
{ "delete":{  "_index" : "ad", "_type" : "phone", "_id" : "1"}}
{ "update":{  "_index" : "ad", "_type" : "phone", "_id" : "3"}}
{ "doc" : {"name" : "huawei p20"}}
复制代码

返回:

{
  "took": 137,
  "errors": true, //如果任意一个文档出错,这里返回true,
  "items": [ //items数组,它罗列了每一个请求的结果,结果的顺序与我们请求的顺序相同
    {
      //create这个文档已经存在,所以异常
      "create": { 
        "_index": "ad",
        "_type": "phone",
        "_id": "6",
        "status": 409,
        "error": {
          "type": "version_conflict_engine_exception",
          "reason": "[phone][6]: version conflict, document already exists (current version [2])",
          "index_uuid": "9F5FHqgISYOra_P09HReVQ",
          "shard": "2",
          "index": "ad"
        }
      }
    },
    {
      //index这个文档已经存在,会覆盖
      "index": { 
        "_index": "ad",
        "_type": "phone",
        "_id": "6",
        "_version": 3,
        "result": "updated",
        "_shards": {
          "total": 2,
          "successful": 1,
          "failed": 0
        },
        "_seq_no": 6,
        "_primary_term": 5,
        "status": 200
      }
    },
    {
      //删除  
      "delete": { 
        "_index": "ad",
        "_type": "phone",
        "_id": "1",
        "_version": 1,
        "result": "not_found",
        "_shards": {
          "total": 2,
          "successful": 1,
          "failed": 0
        },
        "_seq_no": 4,
        "_primary_term": 5,
        "status": 404
      }
    },
    {
      //修改  
      "update": { 
        "_index": "ad",
        "_type": "phone",
        "_id": "3",
        "_version": 3,
        "result": "noop",
        "_shards": {
          "total": 2,
          "successful": 1,
          "failed": 0
        },
        "status": 200
      }
    }
  ]
}
复制代码

bulk请求不是原子操作,它们不能实现事务。每个请求操作时分开的,所以每个请求的成功与否不干扰其它操作

  1. fuzzy查询
    模糊查询,fuzzy 查询会计算与关键词的拼写相似程度
GET /ad/phone/_search
{
  "query": {
    "fuzzy": {
      "color":{
        "value": "res"
        , "fuzziness": 2,
        "prefix_length": 1
      }
    }
  }
}
复制代码

参数设置:

fuzziness:最大编辑距离,默认为AUTO

prefix_length:不会“模糊化”的初始字符数。这有助于减少必须检查的术语数量,默认为0

max_expansionsfuzzy查询将扩展到 的最大术语数。默认为50,设置小,有助于优化查询

transpositions:是否支持模糊转置(abba),默认是false

  1. wildcard查询
    支持通配符的模糊查询,?匹配单个字符,*匹配任何字符
    为了防止极其缓慢通配符查询,*?通配符项不应该放在通配符的开始
GET /ad/phone/_search
{
  "query": {
    "wildcard": {
      "color": "r?d"
    }
  }
}
复制代码

未完待续...

参考: Elasticsearch: 权威指南(版本较老,可以看新的) www.elastic.co/guide/cn/el…