ElasticSearch

Elaticsearch简称es,es是一个开源的高扩展的分布式全文搜索引擎,它可以近乎实现实时存储,检索数据,本身扩展性好,可以扩展到上百台服务器,处理PB级别的数据.es也是用java开发,并使用Lucene作为核心来实现所有和搜索的功能,但是它的目的是通过简单的RestFul API来隐藏Lucene的复杂性,让全文搜索变得简单

2016年,ElasticSearch已经超过solr等,成为排名第一的搜索引擎应用

它用于全文搜索,结构化搜索,分析以及将这三者混合使用

危机便可使用ElasticSearch提供全问搜索并且高亮关键字,以及输入实时搜索(search-asyou-type)和搜索纠错,(did-you-mean)等搜索建议功能.

Elasticearch是一个基于Apache Lucene(TM)的开源搜索引擎.无论是在开源还是专有领域,Luncene开源被认为是迄今为止最先进的,性能最好的全问搜索引擎.

但是,Luncene只是一个库.想要使用它,你必须使用java来作为开发语言并将其直接集成到你的应用中,更糟糕的是,Luncene非常复杂,需要深入了解检索的相关知识来理解它是如何工作的.

使用场景

案例

  1. 维基百科
  2. The Guardian
  3. Stack overFlow
  4. Github
  5. 电商网站
  6. 日志数据分析 logstash采集日志,es进行数据分析 ELK技术,elasticsearch+logstash+kibana
  7. 商品价格监控网站
  8. BI系统

solr

solr是apche下的一个顶级开源项目,采用java开发,是基于Luncene的全文搜索服务器,Solr提供了比Luncene更为丰富的查询语言,同时实现了可配置,可扩展,并对所有,搜索性能进行了优化.

solr开源独立运行在Jetty,Tomcat等这些servlet容器中,solr所有的实现方法很简单,用post方法向solr服务器发送一个描述Field及其内容的XMlL文档,solr根据XML文档添加删除,更新索引.Solr搜索只需发送HTtp get请求,然后对Solr返回XML Json结果进行解析,组织页面布局,Solr不提供构建UI的功能,Solr提供了一个管理界面,通过管理界面可以查询Solr的配置和运行情况

lucene

lucene是apache软件基金会4 jakarta项目中的一个子项目,是一个开放源代码的全问搜索引擎工具包,但它不是一个完整的全问搜索引擎,而是一个全问搜索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎(英文与德文俩种西方语言).lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便在目标系统中实现全文检索功能,或者说以此为基础建立起完整的全文搜索引擎.在java开发环境里lucene是一个成熟的免费开源工具.就其本身而言,lucene是当前以及最简几年最受欢迎的java信息检索程序库.

lucene是一个全文搜索引擎架构,那么什么是全文搜索引擎?

全文搜索引擎是名副其实的搜索引擎,比如Google,Fast,国内的百度.它们都是通过从互联网上提取各个网站的信息,检索与用户查询条件匹配的相关记录,然后按一定的排列顺序返回给用户,因而它们是真正的搜索引擎

比较

Elasticsearch和solr优缺点比较

  • 当单纯的对已有数据进行搜索时,solr更快
  • 当监理索引时,solr会产生io阻塞,elasticsearch具有明显优势
  • 随着数据量的增加,Solr的搜索效率会变得很低,es几乎没有变化

差异

  1. es是开箱即用,Solr安装略微复杂一点
  2. Solr利用zookeeper进行分部署管理,而Elasticsearch自身带有分布式协调管理功能
  3. Solr支持更多格式的数据,比如,json,xml,csv,而es仅支持json文件格式
  4. solr官方提供的功能更多,而es本身更加注重于核心功能,高级功能是第三方插件提供,例如图形需要kibana支撑
  5. solr查询快,但更新慢
  6. solr比较成熟,更大,es维护更新快

搭建

目录

  1. bin 启动文件
  2. config 配置文件

    • log4j2 日志配置文件
    • jvm.options 虚拟机相关配置
    • elasticsearch.yml es的配置文件默认9200端口
  3. lib 相关jar包
  4. log 日志
  5. modules 功能模块
  6. plgins 插件

访问

访问默认的9200端口返回

{
  "name" : "DESKTOP-2PBFFCG",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "l3jmEEiRTIKuegUjuR9ONQ",
  "version" : {
    "number" : "7.6.1",
    "build_flavor" : "default",
    "build_type" : "zip",
    "build_hash" : "aa751e09be0a5072e8570670309b1f12348f023b",
    "build_date" : "2020-02-29T00:15:25.529771Z",
    "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"
}

可视化

插件下载

GitHub - mobz/elasticsearch-head: A web front end for an elastic search cluster

直接npm install 然后npm run start

es文件修改

加上

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

开启跨域

然后访问http://localhost:9100/

索引就类似一个数据库,文档就好比库中的数据

head就当做数据展示工具,后面做的查询都可以去kibana中做

ELK

ELK是Elasticsearch,Logstash,Kibana三大开源框架的简称

Logstash是ELK的中央数据流引擎,用于从不同目标(文件/数据存储/MQ)收集不同格式数据,经过过滤后支持输出到不同的目的地(问/MQ/redis/elasticsearch/kafka等).

Kibana可以将es的数据通过友好的界面展示出来,提供实时的分析功能

Kibana安装

下载解压后的目录

默认Kibana端口5601

开发工具

Kibana汉化

修改kibana.yml

最后一行加上

i18n.locale: "zh-CN"

核心概念

elatiseach是面向文档,和关系型数据库比,一切都是json

RelationalDBElasticsearch
数据库(database)索引(indices)
表(table)types (慢慢会被弃用)
行(row)documents 文档
字段(columns)fields

elasticearch中可以包含多个索引,每个索引中可以包含多个类型,类型中又包含多个文档,每个文档中又包含多个字段

物理设计

elasticsearch在后台把每个索引划分成多个切片,每个分片可以在集群中的不同服务器间迁移

一个es就是一个集群,默认的集群名称就是elasticsearch

逻辑设计

文档

es是面向文档的,这就意味着索引和搜索的最小单位是文档 es中有几个主要的属性,

  • 自我包含,一篇文档同时包含字段和对应的值,也就是同时包含key:value
  • 可以是层次的,一个文档中包含自文档,复杂的逻辑就是这么来的
  • 灵魂的结构,文档不依赖预先定义的模式,我们知道关系型数据库中,要提前定义字段才能使用,es中对于字段是非常灵活的,有时候可以忽略字段,或者动态添加一个字段

监管我们可以随意的新增或者忽略某个字段,但是每个字段的类型非常重要,比如一个年龄类型字段,可以是字符串也可以是整形,因为es会保存字段和类型之间映射以及其他的设置,这种映射具体到每个映射的每种类型,这也是为什么在es中,类型有点时候也称为映射类型

类型

类型是文档的逻辑日期,就像关系型数据库一样,表格是行的容器,类型中对于字段的定义称为映射,比如name映射为字符串类型.我们说文档是无模式的,它们不需要拥有映射所定义的所有字段,比如新增一个字段,那么es是怎么做的呢?es会自动的将新字段假如映射,但是这个字段不确定它是什么类型,es就开始猜,如果这个值是18,那么es就会认为它是整形.但es可能猜不对,所以最安全的方式就是提前定义好所需的映射,这点跟关系型数据库殊途同归.

索引

所以是映射类型的容器,es中的索引是非常大的文档集合,所以存储了映射类型的字段和其他设置.然后他们被存储到各个分片上了.

工作方式

一个集群至少有一个节点,一个节点就是一个es进程,节点可以有多个索引默认的,如果你创建索引,那么索引将会有五个分片构成,又称之为主分片(primary shard)构成的,每一个主分片会有一个副本(replica shard又称为复制分片)

上图是有三个节点的集群,我可以看到主分片和对应的复制分片都不会在同一个节点内,这样有利于某个节点挂掉了,数据也不至于丢失,实际上一个分片是一个lucene索引,一个包含倒排序的文件目录,倒排序索引的结构使得es在不扫描全部文档的情况下,就能告诉你哪些文档包含特定的关键字

倒排序索引

es使用的是一种称为倒排索引的结构,采用lucene倒序作为底层,这种和结构适用于快速的全文搜索,一个索引由文档中所有不重复的列表构成,对于每一个单词,都有一个包含它的文档列表.

为了创建倒排索引,我们首先药将每个文档拆封成独立的词,然后创建一个包含所有不重复的词条的排序列表,然后列出每个词条现在哪个文档

如果俩个文档都匹配,但是第一个文档比第二个文档匹配程度更高,如果没有别的条件,现在,这俩个包含关键字的文档都将被返回

相对于查找所有原始数据而言,查找倒排索引后的数据会快的多.只需要查看标签这一栏,然后获取文章的id即可,完全过滤掉无关的数据

es中索引被分成多个片,每个分片都是lucene所以.所以一个二十索引是多个lucene索引组成的

插件

IK分词器

分词就是把一段中文或者别的划分成一个个的关键字,我们在搜索时候会把自己的信息进行分词查,会把数据库中或者索引库中的数据进行分词,然后进行一个匹配操作,默认的中文分词是每一个字看成一个词,

如果使用中文建议使用ik分词器

GitHub - medcl/elasticsearch-analysis-ik: The IK Analysis plugin integrates Lucene IK analyzer into elasticsearch, support customized dictionary.

下载对应的版本然后拖进插件目录就可以

重启es可以看到ik分词器被加载

输入elasticsearch-plugin list就可以看到插件

使用

什么是ik分词器

IK提供了俩个分词算法,ik_sart和ik_max_word,其中ik_smart为最少切分,ik_max_word为最细粒度划分

在Kibana 中发起请求

GET _analyze
{
  "analyzer": "ik_smart",
  "text": "中国共产党"
}

结果

{
  "tokens" : [
    {
      "token" : "中国共产党",
      "start_offset" : 0,
      "end_offset" : 5,
      "type" : "CN_WORD",
      "position" : 0
    }
  ]
}

如果发送

GET _analyze
{
  "analyzer": "ik_max_word",
  "text": "中国共产党"
}

则返回

{
  "tokens" : [
    {
      "token" : "中国共产党",
      "start_offset" : 0,
      "end_offset" : 5,
      "type" : "CN_WORD",
      "position" : 0
    },
    {
      "token" : "中国",
      "start_offset" : 0,
      "end_offset" : 2,
      "type" : "CN_WORD",
      "position" : 1
    },
    {
      "token" : "国共",
      "start_offset" : 1,
      "end_offset" : 3,
      "type" : "CN_WORD",
      "position" : 2
    },
    {
      "token" : "共产党",
      "start_offset" : 2,
      "end_offset" : 5,
      "type" : "CN_WORD",
      "position" : 3
    },
    {
      "token" : "共产",
      "start_offset" : 2,
      "end_offset" : 4,
      "type" : "CN_WORD",
      "position" : 4
    },
    {
      "token" : "党",
      "start_offset" : 4,
      "end_offset" : 5,
      "type" : "CN_CHAR",
      "position" : 5
    }
  ]
}

如果自己需要加词语到分词器字典中

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"></entry>
     <!--用户可以在这里配置自己的扩展停止词字典-->
    <entry key="ext_stopwords"></entry>
    <!--用户可以在这里配置远程扩展字典 -->
    <!-- <entry key="remote_ext_dict">words_location</entry> -->
    <!--用户可以在这里配置远程扩展停止词字典-->
    <!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>

修改

<?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

如果设置了

GET _analyze
{
  "analyzer": "ik_max_word",
  "text": "那随忆了"
}

就会变成

{
  "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" : 4,
      "type" : "CN_CHAR",
      "position" : 2
    }
  ]
}

(原来是四个字都是分开的

索引基本操作

put新增

创建一个索引

PUT /索引名/类型名/文档id {请求体}

插入

PUT /test1/type1/1
{
  "name": "随亿",
  "age":18
}

结果

#! Deprecation: [types removal] Specifying types in document index requests is deprecated, use the typeless endpoints instead (/{index}/_doc/{id}, /{index}/_doc, or /{index}/_create/{id}).
{
  "_index" : "test1",   //索引
  "_type" : "type1",    //类型
  "_id" : "1",            //id
  "_version" : 1,
  "result" : "created",    //创建状态
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}

在head选中索引就可以进行查看

类型

那么数据库中有哪些常用类型呢

  1. 字符串类型 text,key
  2. 数值类型 long,integer,short,byte,double,float,half float,scaled float
  3. 日期类型 date
  4. 布尔值类型 boolean
  5. 二进制类型 binary
  6. 等等

自己设置类型

PUT /test2
{
  "mappings": {
    "properties": {
      "name":{
        "type":"text"
      },
      "age":{
        "type":"long"
      },
      "birthday":{
        "type":"date"
      }
    }
  }
}

类似于建立数据表

返回

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

创建成功

然后用GET test2查看表结构获取具体信息

{
  "test2" : {
    "aliases" : { },
    "mappings" : {
      "properties" : {
        "age" : {
          "type" : "long"
        },
        "birthday" : {
          "type" : "date"
        },
        "name" : {
          "type" : "text"
        }
      }
    },
    "settings" : {
      "index" : {
        "creation_date" : "1652755677562",
        "number_of_shards" : "1",
        "number_of_replicas" : "1",
        "uuid" : "YqkoIej5RxusmWOWZhqfxw",
        "version" : {
          "created" : "7060199"
        },
        "provided_name" : "test2"
      }
    }
  }
}

之后默认就是doc类型的了

PUT /test3/_doc/1
{
  "name":"那随意了",
  "age":13,
  "birth":"1997-01-05"
}

结果

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

这时候查看当前创建的类型会发现

{
  "test3" : {
    "aliases" : { },
    "mappings" : {
      "properties" : {
        "age" : {
          "type" : "long"
        },
        "birth" : {
          "type" : "date"
        },
        "name" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    },
    "settings" : {
      "index" : {
        "creation_date" : "1652755917555",
        "number_of_shards" : "1",
        "number_of_replicas" : "1",
        "uuid" : "p8yTyYYlSkm6X06KJ2x58Q",
        "version" : {
          "created" : "7060199"
        },
        "provided_name" : "test3"
      }
    }
  }
}

如果文档没指定,文档会自动生成类型

其他命令

GET _cat/health获取健康值

GET _cat/indices?v查看数据库的具体信息

修改索引

修改还是使用put,覆盖最新值即可

比如

PUT /test3/_doc/1
{
  "name":"那随忆了",
  "age":13,
  "birth":"1997-01-05"
}

值就被成功修改了

结果

{
  "_index" : "test3",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 2,        //版本号增加了
  "result" : "updated",    //状态为updated
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 1,
  "_primary_term" : 1
}

以上是曾经的方法,有一个弊端,万一漏了一条数据那么那个数据就丢失了比如age

post修改

POST /test3/_doc/1/_update
{
  "doc":{
    "name":"张三"
  }
}

结果

#! Deprecation: [types removal] Specifying types in document update requests is deprecated, use the endpoint /{index}/_update/{id} instead.
{
  "_index" : "test3",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 3,    //变为第三个版本了
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 2,
  "_primary_term" : 1
}

如果最后不加/_update那么就和put没有区别了

删除索引

DELETE test1

根据请求来判断是删除索引还是删除文档记录

删单条数据DELETE test1/type1/1

查询

单条记录

GET test3/_doc/1

全表

GET test3

GET test3/_doc/_search搜索全表

GET test3/_doc/_search?q=name:张或者GET test3/_doc/_search?q=name:张三

(精确匹配

结果

#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
  "took" : 29,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.5753642,
    "hits" : [
      {
        "_index" : "test3",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.5753642,
        "_source" : {
          "name" : "张三",
          "age" : 13,
          "birth" : "1997-01-05"
        }
      }
    ]
  }
}

注意! 分词器对keyword字段不会工作

复杂查询

"_score" : 0.5753642,这个字段代表着分数,如果多条记录中,匹配度越高分值则越高

GET test3/_doc/_search
{
  "query":{
    "match": {
      "name": "张三"
    }
  }
}

返回结果

#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,        
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,         //数量
      "relation" : "eq"    //关系
    },
    "max_score" : 0.5753642,//最大分值
    "hits" : [
      {
        "_index" : "test3",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.5753642,
        "_source" : {
          "name" : "张三",
          "age" : 13,
          "birth" : "1997-01-05"
        }
      }
    ]
  }
}

hit中能获取索引和文档的信息,查询的结果总数,然后就是查询出来的具体的文档,数据中的东西都可以遍历出来了,我们可以通过分数来判断谁更加符合结果

可以通过_source来指定要查询出来的字段

GET test3/_doc/_search
{
  "query":{
    "match": {
      "name": "张三"
    }
  },
  "_source":["name","age"]
}

结果

#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 2.0834165,
    "hits" : [
      {
        "_index" : "test3",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 2.0834165,
        "_source" : {
          "name" : "张三",
          "age" : 13
        }
      }
    ]
  }
}

排序和分页

假如有以下数据

传入

GET test3/_doc/_search
{
  
  "sort":[
    {
      "age":{
        "order":"asc"    //排序方式
      }
    }
  ],
  "from":0,                //第几条开始
  "size":3                //数量
}

结果

#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [
      {
        "_index" : "test3",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : null,
        "_source" : {
          "name" : "张三",
          "age" : 13,
          "birth" : "1997-01-05"
        },
        "sort" : [
          13
        ]
      },
      {
        "_index" : "test3",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : null,
        "_source" : {
          "name" : "qwq",
          "age" : 18,
          "birth" : "2000-01-05"
        },
        "sort" : [
          18
        ]
      },
      {
        "_index" : "test3",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : null,
        "_source" : {
          "name" : "阿巴阿巴",
          "age" : 20,
          "birth" : "2000-08-05"
        },
        "sort" : [
          20
        ]
      }
    ]
  }
}

多个条件

must(类似and)所有条件都要符合

GET test3/_doc/_search
{
  "query":{
    "bool":{
      "must":[
          {
            "match":{
              "name":"张三"
            }
          },
          {
            "match":{
              "age":13
            }
          }
      ]
    }
  }
}

返回

#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
  "took" : 17,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 3.0834165,
    "hits" : [
      {
        "_index" : "test3",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 3.0834165,
        "_source" : {
          "name" : "张三",
          "age" : 13,
          "birth" : "1997-01-05"
        }
      }
    ]
  }
}

should (类似or)

GET test3/_doc/_search
{
  "query":{
    "bool":{
      "should":[
          {
            "match":{
              "name":"张三"
            }
          },
          {
            "match":{
              "age":131
            }
          }
      ]
    }
  }
}

结果

#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 2.0834165,
    "hits" : [
      {
        "_index" : "test3",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 2.0834165,
        "_source" : {
          "name" : "张三",
          "age" : 13,
          "birth" : "1997-01-05"
        }
      }
    ]
  }
}

must_not (类似于not)

请求

GET test3/_doc/_search
{
  "query":{
    "bool":{
      "must_not":[
          {
            "match":{
              "name":"张三"
            }
          },
          {
            "match":{
              "age":131
            }
          }
      ]
    }
  }
}

结果

#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 0.0,
    "hits" : [
      {
        "_index" : "test3",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.0,
        "_source" : {
          "name" : "qwq",
          "age" : 18,
          "birth" : "2000-01-05"
        }
      },
      {
        "_index" : "test3",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.0,
        "_source" : {
          "name" : "阿巴阿巴",
          "age" : 20,
          "birth" : "2000-08-05"
        }
      }
    ]
  }
}

如果需要查询大于15岁小于50的年龄

GET test3/_doc/_search
{
  "query":{
    "bool":{
      "filter":{
        "range":{
          "age":{
            "gt":15,
            "lt":50
          }
        }
      }
    }
  }
}
  • gt:大于
  • gte 大于等于
  • lt 小于
  • lte 小于等于

结果

#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 0.0,
    "hits" : [
      {
        "_index" : "test3",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.0,
        "_source" : {
          "name" : "qwq",
          "age" : 18,
          "birth" : "2000-01-05"
        }
      },
      {
        "_index" : "test3",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.0,
        "_source" : {
          "name" : "阿巴阿巴",
          "age" : 20,
          "birth" : "2000-08-05"
        }
      }
    ]
  }
}

也可以这样查询

GET test3/_doc/_search
{
  "query":{
    "match":{
      "name":"qwq 张三"
    }
  }
}

结果

#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 2.0834165,
    "hits" : [
      {
        "_index" : "test3",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 2.0834165,
        "_source" : {
          "name" : "张三",
          "age" : 13,
          "birth" : "1997-01-05"
        }
      },
      {
        "_index" : "test3",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.2800651,
        "_source" : {
          "name" : "qwq",
          "age" : 18,
          "birth" : "2000-01-05"
        }
      }
    ]
  }
}

精确查询

term查询是通过倒排序所以指定的词条进行精确查找的

关于分词

term,直接精确查询的

match,会使用分词器解析

text会被分词解析,keyword不会

先插入测试数据

PUT testdb
{
  "mappings": {
    "properties": {
      "name":{
        "type":"text"
      },
      "desc":{
        "type":"keyword"
      }
    }
  }
}

PUT testdb/_doc/1
{
  "name": "随意的java博客",
  "desc":"随意的java世界"
}
PUT testdb/_doc/2
{
  "name": "随意的php博客",
  "desc":"随意的php世界"
}

测试请求

GET testdb/_search
{
  "query":{
    "term": {
      "name": "随"
    }
  }
}
GET testdb/_search
{
  "query":{
    "term": {
      "desc": "随"
    }
  }
}

第一个请求会返回

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 0.18232156,
    "hits" : [
      {
        "_index" : "testdb",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.18232156,
        "_source" : {
          "name" : "随意的java博客",
          "desc" : "随意的java世界"
        }
      },
      {
        "_index" : "testdb",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.18232156,
        "_source" : {
          "name" : "随意的php博客",
          "desc" : "随意的php世界"
        }
      }
    ]
  }
}

高亮查询

GET testdb/_search
{
  "query":{
    "term": {
      "name": "随"
    }
  }
  , "highlight": {
      "pre_tags": "<p>",        //自定义前缀
      "post_tags": "</p>",         //后缀
      "fields": {
        "name":{}
      }
  }
}

返回

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 0.18232156,
    "hits" : [
      {
        "_index" : "testdb",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.18232156,
        "_source" : {
          "name" : "随意的java博客",
          "desc" : "随意的java世界"
        },
        "highlight" : {
          "name" : [
            "<p>随</p>意的java博客"
          ]
        }
      },
      {
        "_index" : "testdb",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.18232156,
        "_source" : {
          "name" : "随意的php博客",
          "desc" : "随意的php世界"
        },
        "highlight" : {
          "name" : [
            "<p>随</p>意的php博客"
          ]
        }
      }
    ]
  }
}
Last modification:September 13, 2022
如果觉得我的文章对你有用,请随意赞赏