迎着风跑  

Elastic Search 进阶

#1. 操作索引

ES 集群可以包含:

  • 多个索引(indices)。类比 SQL 领域中的数据库(database)

  • 每一个索引(index)中可以包含多个类型(types)。类比 SQL 领域中的表(table)不过 type 的概念在弱化,可使用 _doc 关键字代替。

  • 每一个类型包含多个文档(documents),类比于 SQL 领域中的行(row)

  • 然后每个文档(document)包含多个字段(Fields),类比于 SQL 领域中的列(Column)

#创建索引

PUT 索引名
Copied!

返回结果显示 acknowledged 的值为 true,说明新建索引成功。

索引名中不能含有大写字母。

Elasticsearch 默认给一个索引设置 5 个分片 1 个副本,一个索引的分片数一经指定后就不能再修改,副本数可以通过命令随时修改。

如果想创建自定义分片数和副本数的索引,可以通过 setting 参数在创建索引时设置初始化信息。

  • 例如,指定创建 3 个分片 0 个副本:

    PUT 索引名
    {
      "settings" : {
        "number_of_shards" : 3,
        "number_of_replicas" : 0
      }
    }
    
    Copied!

在创建索引之后,也可修改其索引的副本数。

  • 例如,将名为 xxx 的索引的副本数修改为 3 使用如下命令:

    PUT xxx/_settings
    {
      "number_of_replicas" : 3
    }
    
    Copied!

#删除索引

索引的删除只需要使用 DELETE 方法,传入要删除的索引名即可。注意,一旦执行删除操作索引中的文档就不服存在。

  • 删除名为 xxx 的索引,命令如下:

    DELETE xxx
    
    Copied!
  • 如果删除成功,会有以下响应:

    {
      "acknowledged" : true
    }
    
    Copied!

尝试删除一个不存在的索引,会报 索引未找到 异常。

#查看索引(了解、自学)

使用 GET 方法加上 _setting 参数可以查看一个索引的所有配置信息。

GET xxx/_settings

GET xxx,yyy,zzz/_settings

GET _all/_settings
Copied!

#2. 增删改文档

Elasticsearch 中文档的增删改查和关系型数据库操作非常相似。

#新建文档(插入新的文档)

PUT 索引名/_doc/手动指定ID值
{
  "field1" : "value1",
  "field2" : "value2",
  "field3" : "value3",
  ...
}
Copied!

例如:

PUT books/_doc/1
{ 
  "id" : "1", 
  "title" : "Java 编程思想", 
  "language" : "java", 
  "author" : "Bruce Eckel", 
  "price": 70.20, 
  "publish_date" : "2007-10-01", 
  "description" : "Java 学习必读经典,殿堂级著作!赢得了全球程序员的广泛赞誉。" 
}
Copied!

如果没有出现错误,Elasticsearch 服务器会返回一个 JSON 格式的响应信息中会有 "created": true 信息。

当然,你也可以直接通过查询命令以验证你是否插入成功:

GET /索引名/_doc/ID值/_source

GET /索引名/_doc/_search
Copied!

向索引中新加文档时,如果你没有手动指定文档的 ID,那么 Elasticsearch 会自动生成它的 ID 。不过,此时需要使用 POST 命令,而非 PUT 命令。

POST books/_doc
{ 
  "id" : "1", 
  "title" : "Java 编程思想", 
  "language" : "java", 
  "author" : "Bruce Eckel", 
  "price": 70.20, 
  "publish_date" : "2007-10-01", 
  "description" : "Java 学习必读经典,殿堂级著作!赢得了全球程序员的广泛赞誉。" 
}
Copied!

#删除文档

Delete API 允许基于指定的 ID 从索引库中删除一个文档。

DELETE /索引名/_doc/ID值
Copied!

例如:

DELETE /books/_doc/1
Copied!

删除成功后,Elasticsearch 返回的信息中会给出类似 "found" : true, "result" : "deleted" 信息。

#查询删除

POST /索引名/_doc/_delete_by_query
{
  "query" : {
    "term": {
      "FIELD1": "VALUE1",
      ...
    }
  }
}
Copied!

如果是无条件删除所有文档,那么语法是:

POST 索引名/_doc/_delete_by_query
{
  "query" : {
    "match_all" : {}
  }
}
Copied!

#更新文档

文档被索引之后,如果要更新,那么 Elasticsearch 内部首先要找到这个文档,删除旧的文档内容执行更新,更新完之后再索引最新的文档。

  • 语法:

    POST 索引名/_doc/id值
    {
      "field1" : "value1",
      "field2" : "value2",
      "field3" : "value3",
      ...
    }
    
    Copied!

该命令与新增文档命令「看起来很像」,唯一不同的就是 PUT 请求变为 POST 请求。

  • 执行成功时,返回的信息中我们可以看到 已更新,以及增加后的版本号。

    {
      ...
      "_version" : xxx,
      "result" : "updated",
    }
    
    Copied!

再次强调,更新的底层原理是『先删除后增加』。

POST 请求总结:

  • 不带 ID 时,是新增操作,并且是要求 ElasticSearch 为新增数据的 _id 赋值。

  • 带 ID 时,是修改操作,通过携带的 ID 来指定要修改那条数据。

#局部更新文档

接受一个局部文档参数 doc,它会合并到现有文档中,对象合并在一起,存在的标量字段被覆盖,新字段被添加。

  • 语法:

    POST 索引值/_doc/id值/_update
    {
      "doc" : {
        "field1" : "value1",
        "field2" : "value2",
        "field3" : "value3",
        ...
      }
    }
    
    Copied!

局部更新仍旧也是先删除旧文档,再重新添加新文档。

#映射

映射也就是 Mapping ,用来定义一个文档(Document)以及其包含的字段如何被存储和索引,可以再映射中事先定义字段的数据类型、分词器等属性。

简单来说,Elasticsearch 中的映射就如同数据库领域中的表定义。

映射可分为『动态映射』和『静态映射』。

动态映射就是文档在写入 Elasticsearch 时,由 Elasticsearch 根据字段的类型自动识别。而静态映射就如同表定义,在写入数据之前对字段的属性进行手工设置。

动态映射是一种偷懒的方式,在创建索引(index)后,直接去插入文档,跳过定义的环节,而由 Elasticsearch 根据插入的文档的数据来自己识别。

Elasticsearch 自动推测字段类型的规则

JSON 格式的数据自动推测的字段类型
null 没有字段被添加
true or false boolean 类型
浮点类型数字 float 类型
数字 long 类型
JSON 对象 object 类型
数组 由数组中第一个非空值决定
string 有可能是 date 类型、double 类型或 long 类型、text 类型、keyword 类型

动态映射看似很方便,但是有一个缺点:它使用的是默认的分词器(standard),特别是对于我们中文环境而言,这简直就是致命缺点。

因此,通常我们在创建完索引之后,会手动创建映射:

PUT /索引名称/_mapping
{
  "properties": {
    "属性名" : { "type": "类型" },
    "属性名" : { "type": "keyword" },
    "属性名" : { "type": "text", "analyzer": "分词器分词方式" },
    "属性名" : { "type": "date", "format": "格式1 || 格式2 || ..." },
    ...
  }
}
Copied!

例如,素材 中的 mapping 命令:

PUT /books/_mapping
{
  "properties": {
    "id"      : { "type": "keyword" },
    "title"   : { "type": "text", "analyzer": "ik_smart" },
    "language": { "type": "keyword" },
    "author"  : { "type": "keyword" },
    "price"   : { "type": "float" },
    "publish_date"  : { "type": "date", "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" },
    "description"   : { "type": "text", "analyzer": "ik_max_word" } 
  }
}
Copied!

查看索引的 mapping ,命令如下:

GET xxx/_mapping
Copied!

如果你输入字符串看起来像日期(例如:2000-1-1),那么 Elasticsearch 会将它识别为一个 date 类型的字段。

另外,Elasticsearch 5.X 之后的字段类型不再支持 string ,而是由 text 和 keyword 取代。

  • text 类型的字段中的数据会被分词,以支持全文索引;

  • keyword 类型的字段只能作为一个整体被精确搜索。

#3. 查询文档

Elasticsearch 提供了 GET API 查看在其中所存储的文档(Document),使用 GET 命令并指定文档所在的索引(index)、类型(type)和 id 即可返回一个 JSON 格式的文档(Document)

如果所查看的文档存在,返回的信息中会含有 "found" : true,反之,则会含有 "found" : false 。

#简单查询

#根据 ID 查询

GET /索引名/_doc/id值
Copied!

#空查询

空查询是指没有指定任何查询条件的查询。这种情况下,返回的是所有文档:

GET 索引名/_doc/_search
Copied!

例如:

GET books/_doc/_search
Copied!

你会看到,es 在建议你,不用写 _doc 关键字。即,写成:

GET 索引名/_search
Copied!

#分页查询

Elasticsearch 提供了两个结果分页的属性:

分页属性说明
from 指定返回结果的开始位置。默认值为 0 。
size 指定一次性返回结果包含的最大文档数量。
# GET /books/_doc/_search
GET /books/_search
{
  "from" : 0,
  "size" : 100
}
Copied!

#显示版本号

默认情况下返回结果中不包含文档的版本号,如果需要,可以在查询体中设置 version 属性为 true 。

GET books/_search
{
  "version" : true
}
Copied!

#排序

当搜索的字段有多个时,可以指定字段进行排序。

GET books/_search
{
  "sort" : [
    { "price": { "order" : "desc" } },
    { "publish_date": { "order": "asc" } }
  ]
}
Copied!

#数据列过滤

数据列过滤允许在查询的时候不显示原始数据,或者显示部分原始数据。

GET books/_search
{
  "_source" : false
}

GET books/_search
{
  "_source" : ["id", "price"]
}
Copied!

#词项(term)查询

词项查询是对倒排序索引中存储的词进行精确操作。词项级别的查询通常用于结构化数据,如数字,日期。

#term 查询

term 查询用来查找 所指定的字段中包含给定单词 的文档。term 查询『不会被解析』,只有查询词和文档中的词精确匹配才会被搜索到。应用场景为查询人名、地名等需要精确匹配的需求。

查询命令如下:

GET books/_search
{
  "query" : {
    "term" : { "title" : "思想" }
  }
}
Copied!

#返回部分字段信息

默认情况下,返回的结果中包含了文档的所有字段信息,有时候为了简洁,只需要在查询结果中返回某些字段。

GET books/_search
{
  "_source" : ["title", "author"],
  "query" : {
    "term" : { "title" : "思想" }
  }
}
Copied!

#返回版本号

默认情况下,返回的结果中不包含文档的版本号,如果需要,可以在查询体中设置 version 属性为 true 。

GET books/_search
{
  "version" : true,
  "query" : {
    "term" : { "title" : "思想" }
  }
}
Copied!

#最小评分过滤

Elasticsearch 提供了基于最小评分的过滤机制,通过这种机制,可以过滤/排除掉查询结果中相关性较低的结果。

GET books/_search
{
  "min_score" : 0.6,
  "query" : {
    "term" : { "title" : "思想" }
  }
}
Copied!

#terms 查询

terms 查询是 term 查询的升级版,可以用来查询文档中包含多个词的文档。

比如,想查询 title 字段中包含 java 或 python 的文档。

GET books/_search
{
  "query" : {
    "terms" : { 
      "title" : ["java","python"]
    }
  }
}
Copied!

#全文(text)查询

全文搜索通常用于在全文(text)字段上进行搜索。

Elasticsearch 取消了 string 类型,取而代之的是 text 类型和 keyword 类型。

两者的区别在于:text 类型的字段中存储的字符串会被分词器分词,而 keyword 类型字段中存储的字符串则被当作一个整体看待。

在执行全文搜索前,所要查询的字段的分词器会应用于查询字符串,对其进行分词。

#match 查询

如果你进行的是 match 查询,那么,你所提供的查询条件会被分词。即,

你以为你提供的只是一个查询条件,其实你提供了一堆查询条件,而这是一堆条件之间是『或』 的关系。

GET books/_search
{
  "query" : {
    "match" : {
      "title" : "java编程"
    }
  }
}
Copied!

match 查询会对查询语句进行分词,分词后查询语句中的任何一个词项被匹配,文档即被选中。

TIP

想知道中文字符串被分词器解析出几个词项,可以通过下面命令简介知道:

POST _analyze
{
  "analyzer" : "ik_max_word 或 ik_smart",
  "text" : "内容"
}

# 查看某个字段的分词结果
GET 索引名/_doc/指定ID/_termvectors?fields=字段名
Copied!

如果想查询匹配所有关键词的文档,可以用 and 操作符连接。

GET books/_search
{
  "query" : {
    "match" : {
      "title" : {
        "query" : "java编程思想",
        "operator" : "and"
      }
    }
  }
}
Copied!

#match_phrase 查询

match_phrase 查询首先会把 query 内容分词,分词器可以自定义,同时文档还要满足以下两个条件才会被搜索到:

  • 分词后所有词都要出现在该字段中
  • 字段中词项顺序要一直
GET test/_search
{
  "query" : {
    "match_phrase" : {
        "foo" : "hello world"
    }
  }
}
Copied!
  • { "foo" : "I just said hello world" } 会被选中
  • { "foo" : "Hello world" } 会被选中
  • { "foo" : "World hello" } 则不会

#multi_match 查询

multi_match 查询是 match 查询的升级版,用于搜索多个字段。

查询条件为 java 编程,查询域为 title 和 description

GET books/_search
{
  "query" : {
    "multi_match" : {
      "query" : "java编程",
      "fields" : ["title", "description"]
    }
  }
}
Copied!

multi_match 支持对要搜索的字段的名称使用通配符:

"fields" : ["title", "*_name"]
Copied!

#其它查询

#range 查询

range 查询用于匹配在某一范围内的数值型、日期类型的文档。比如搜索哪些书籍的价格在 50 到 100 之间,哪些书籍的出版日期在 2014 年到 2016 年之间。

使用 range 查询只能查询一个字段,不能作用于多个字段上。

range 查询支持的参数有以下几种:

参数说明
gt 大于。查询范围的最小值,也就是下限,但不包含临界值。
gte 大于等于。和 gt 的区别在于包含临界值。
lt 小于。查询范围的最大值,也就是上限,但不包含临界值。
lte 大于等于。和 lt 的区别在于包含临界值。
GET books/_search
{
  "query" : {
    "range" : {
      "price" : {
        "gt" : 50,
        "lte" : 70
      }
    }
  }
}


GET books/_search
{
  "query" : {
    "range" : {
      "publish_date" : {
        "gte" : "2016-01-01",
        "lte" : "2016-12-31",
        "format" : "yyyy-MM-dd"
      }
    }
  }
}
Copied!

#exists 查询

exists 查询会返回字段中至少有一个非空值的文档。例如:

GET books/_search
{
  "query" : {
    "exists" : {
      "field" : "user"
    }
  }
}
Copied!

对于上述情况,被选中的文档会有:

· { "user" : "tom" }
· { "user" : "" }
· { "user" : "-" }
· { "user" : ["tom"] }
· { "user" : ["tom", null] }
Copied!

不会被选中的文档有:

· { "user" : null }
· { "user" : null }
· { "user" : [] }
· { "user" : [null] }
· { "hello" : "world" }
Copied!

#prefix 查询

prefix 查询用于查询某个字段中『以给定前缀开始』的文档。

比如,查询 title 中以 java 为前缀的文档,那么含有 javajavascriptjavaee 等以 java 开头的关键词的文档都会被选中。

GET books/_search
{
  "query" : {
    "prefix" : {
      "title" : "java"
    }
  }
}
Copied!

注意

prefix 查询性能并不很高,需要消耗较多的 CPU 资源。

#wildcard 查询

wildcard 查询就是通配符查询,支持单字符和多字符通配。

? 用来匹配任意一个字符,* 用来匹配零个或多个字符。

注意

和 prefix 查询一样,wildcard 查询的查询性能也不是很高。

GET books/_search
{
  "query" : {
    "wildcard" : {
      "author" : "张*"
    }
  }
}
Copied!

#复合查询

复合查询就是把一些简单查询组合在一起实现更复杂的查询需求。

#bool 查询

bool 查询可以把任意多个简单查询组合在一起,使用 mustshouldmust_notfilter 选项来表示简单查询之间的逻辑。每个选项都可以出现 0 到多次,具体含义如下:

选项说明
must 文档必须匹配 must 选项下的查询条件,相当于 AND 。
should 文档可以匹配 should 选项下的条件,也可以不匹配。相当于 OR 。
must_not 与 must 相反,匹配该选项下的查询条件的文档会被排除,不显示。
filter 和 must 一样,匹配 filter 选项下的条件的文档才会被选中,显示。但 filter 不评分,只起到过滤功能。
{
    "match": { "title": "brown fox"}
}
Copied!

实际上相当于就是:

// 命中的数据的 tittle 可以有 brown(也可以没有),可以有 fox(也可以没有)。
// 两个条件都是可以有(也可以没有)。
{
  "bool": {
    "should": [
      { "term": { "title": "brown" }},
      { "term": { "title": "fox"   }}
    ]
  }
}
Copied!

{
    "match": {
        "title": {
            "query":    "brown fox",
            "operator": "and"
        }
    }
}
Copied!

相当于就是:

// 命中的数据的 tittle 必须有 brown ,必须有 fox 。
// 两个条件都是必须有。
{
  "bool": {
    "must": [
      { "term": { "title": "brown" }},
      { "term": { "title": "fox"   }}
    ]
  }
}
Copied!

例如:

// 命中的数据的 tittle 必须有 brown ,desciption 中可以有“虚拟机”(也可以没有),price 必须不能大于等于 70 。
GET books/_search
{
  "query" : {
    "bool" : {
      "must" : [{
        "match" : { "title" : "java" }
      }],
      "should" : [{
        "match" : { "description" : "虚拟机"} 
      }],
      "must_not" : [{
        "range" : {"price" : { "gte": 70 }}
      }]
    }
  }
}
 
posted on 2021-12-08 20:16  迎着风跑  阅读(157)  评论(0编辑  收藏  举报