ZBlog

1567668608251

Elasticsearch

Elasticsearch简介

​ Elasticsearch是一个实时分布式搜索和分析引擎。它对Lucene进行了封装。能够满足实时搜索的稳定、可靠、快速等。基于REST接口。

ES与MySQL的对比

Elasticsearch MySQL
index 索引库 database 数据库
type 类型 table 类型
document 文档 row 行
field 字段 column 列

Elasticsearch安装部署

  1. 安装JDK版本最好在1.8以上(因为这个比较基础就不详细解释了)

  2. 下载Elasticsearch

  3. 下载完成以后上传到Linux系统中,解压

  4. 进入到解压后的文件中尝试进行开启

    • bin/elasticsearch (-d 后台运行)
    • 注意:需要关闭机器的防火墙(service iptables stop)关闭开机自启动(chkconfig iptables off)
    • 会发现执行报错 就是不可以在root用户下打开,选择一个其他用户就可以了
    • 1566398085045
  5. 修改配置变量

    • 修改Elasticsearch中config变量 (vi config/elasticsearch.yml)

    • 增加两行代码

      1
      2
      bootstrap.system_call_filter: false  
      network.host: 192.168.32.110 //后面的的IP设置你自己的本地IP就可以
  • 1566398675928

  • 修改Linux的配置变量

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    vi /etc/security/limits.conf
    * soft nofile 65536
    * hard nofile 131072
    * soft nproc 2048
    * hard nproc 4096
    vi /etc/sysctl.conf
    vm.max_map_count=262144
    vi /etc/security/limits.d/90-nproc.conf
    把1024修改为4096
    * soft nproc 4096
  • 修改完配置以后重启操作系统在启动就可以啦

  • 启动之后出现以下情况

  • 1566456097622

  • 没有报错就表示启动成功了 这时候jps查看进程就可以看到Elasticsearch了

  • 1566456158512

  • 然后可以使用web界面查看 在浏览器输入 http://yourip:9200 就可以查看了

简单基本操作

CURL简介

  • curl起始就是一个可以在命令行下访问URL的工具
  • curl可以利用URL语法在命令行的方式下操作开源的文件
  • 这样即可以方便我们其他不同部门对我们数据库的操作,也方便我们管理数据库,方便管理其他用户的权限

CURL的简单操作

  • -x 是指定http请求的方法

    • 他的类型有很多种包括 GET POST PUT DELETE 查询、修改、增加、删除等很多操作
  • -d 是指需要传递的参数

  • 首先我们先创建一个简单的索引

  • 然后我们可以创建一个索引并为创建的索引添加一些内容然后进行一些列查询

    • 1
      2
      3
      4
      5
      6
      curl -H "Content-Type: application/json" //—H指定添加内容的类型为json类型
      -XPOST http://localhost:9200/test/emp/1 //1是指定索引的IP 不加系统也会自动生成
      -d '{
      "name" : "tom",
      "age" : 25
      }' //加入索引中的具体内容
    • 1566458468549

    • 查询我们刚刚创建的索引

    • 1
      curl -XGET http://localhost:9200/test/emp/1?pretty
    • 1566458541679

    • 检索索引中的一部分内容

    • 1
      curl -XGET 'http://localhost:9200/test/emp/1?_source=name&pretty'
    • 1566458667647

    • 查询指定索引库指定类型的所有数据

    • 1
      2
      curl -XGET http://hadoop110:9200/test/emp/_search?pretty 
      查看tem类型下的所有数据
    • 1566458873757

  • 对ES进行更新操作,ES中可以使用put或者post两种方式进行更新操作

    • 执行更新操作的时候ES的操作细节

      • 首先将旧的文件标记为删除状态
      • 添加新的文件
      • 旧文件不会立即消失但是我们看不见
      • ES在后续你添加更多文件的时候在后台清理掉标记为删除状态的文件
    • 执行局部更新的操作

    • 1
      curl -H "Content-Type: application/json" -XPOST  http://hadoop110:9200/test/emp/1/_update -d '{"doc":{"age":20}}'
    • 我们接着进行一次查询看数据是否已经更新

    • 1566459328843

    • 可以看到年龄已将改成20了 所以说明更新操作成功了 我们可以根据这个操作做很多事情

  • 对ES进行删除操作

    • 删除我们之前创建的索引

    • 1
      curl -XDELETE http://hadoop110:9200/test/emp/1
    • 删除以后我们在进行get获取操作就会报错说明我们的删除操作已经执行成功了

    • 1566459547355

    • 如果删除文档存在 则会返回:200 ok的状态码,found属性值为true,_version属性的值+1

    • 如果想要删除的文件不存在就会返回:404 NotFound的状态码,found属性值为false,但是_version属性的值依然会+1,这个就是内部管理的一部分,它保证了我们在多个节点间的不同操作的顺序都被正确标记了

  • 对ES进行批量操作 包括很多步的增删改查等

    • 批量操作就是bulk API帮助我们同时执行多个操作

    • 语法的格式:

    • 1
      2
      3
      4
      5
      6
      action:index/create/update/delete  //需要执行的操作类型
      metadata:_index,_type,_id //指定需要操作的索引的索引库、类型、ID等
      request body:_source(删除操作不需要)
      { action: { metadata }} //具体要执行的操作
      { request body }
      .........
    • create与index的区别

      • 在创建数据时,如果数据已存在 create会返回创建失败,文件已存在,但是index会执行成功
    • 使用方法: 我们创建一个文件保存我们需要执行的操作

    • 1
      2
      3
      4
      5
      vi requests
      { "index" : {"_index":"test","_type":"emp","_id":"21"}}
      { "name" : "test21"}
      执行:
      curl -H "Content-Type: application/json" -XPUT localhost:9200/test/emp/_bulk --data-binary @requests
    • 1566461216320

    • 出现下面结果表示执行成功了

    • 我们可以放多条指令进去 同时执行多条指令但是要保证中间格式不出错

插件的介绍

Elasticsearch Head Plugin站点插件可以以网页形式展现ES

  • 注意:这个插件依赖于nodejs,phantomjs所以我们在安装插件之前需要安装nodejs以及grunt

    • nodejs下载地址https://nodejs.org/dist/v10.15.3/node-v10.15.3-linux-x64.tar.xz

    • 因为此文件是.tar.xz,所以需要先使用xz解压在使用tar解压 如果解压xz的命令不存在就需要使用yum进行下载 yum -y install xz

    • 1
      2
      3
      解压:
      xz -d node-v10.15.3-linux-x64.tar.xz
      tar -xvf node-v10.15.3-linux-x64.tar
    • 创建软连接

    • 1
      2
      ln -s /data/soft/node-v10.15.3-linux-x64/bin/node  /usr/bin/node
      ln -s /data/soft/node-v10.15.3-linux-x64/bin/npm /usr/bin/npm
    • 设定nodejs安装软件的dialing服务器

    • 1
      npm config set registry https://registry.npm.taobao.org
    • 安装grunt

    • 1
      2
      npm install -g grunt 
      npm install -g grunt-cli
    • 创建软连接

    • 1
      ln -s /data/soft/node-v10.15.3-linux-x64/bin/grunt  /usr/bin/grunt
    • 安装phantomjs

    • 解压

    • 1
      2
      bzip2 -d phantomjs-2.1.1-linux-x86_64.tar.bz2
      tar -xvf phantomjs-2.1.1-linux-x86_64.tar
    • 创建软连接

    • 1
      ln -s /data/soft/phantomjs-2.1.1-linux-x86_64/bin/phantomjs  /usr/bin/phantomjs
    • 安装依赖软件

    • 1
      yum -y install wget fontconfig
  • 安装head插件

    • 下载地址:https://github.com/mobz/elasticsearch-head/archive/master.zip

    • 解压 需要使用unzip命令

    • 下载unzip

    • 1
      yum install -y unzip
    • 解压

    • 1
      unzip elasticsearch-head-master.zip
    • 然后cd进入到解压的文件中

    • 安装两个插件

    • 1
      2
      npm audit fix
      npm audit fix --force
    • 执行安装命令安装head

    • 1
      sudo npm install
    • 启动之前修改Gruntfile.js文件,增加hostname参数

    • 1
      2
      3
      4
      5
      6
      7
      vi Gruntfile.js
      options: {
      hostname: 'hadoop100',
      port: 9101,
      base: '.',
      keepalive: true
      }
    • 启动服务

    • 1
      grunt Server
    • 启动服务后还需要修改Elasticsearch中的一些配置

    • 1
      2
      3
      vi config/elasticsearch.yml
      http.cors.enabled: true
      http.cors.allow-origin: "*"
    • 修改完成后重启ES

    • 进入网址http://hadoop100:9101/可以看到以下信息就说明插件安装成功了

    • 1566465169785

配置参数详解

  • 配置文件elasticsearch.yml
  • ES已经为大多数的参数设置了合理的默认值 我们只需要在有特殊需求的时候进行修改
  • 书写规范
    • 属性顶格写,不能有空格
    • 缩进一定要是用空格而不能使用制表符
    • 属性与属性值之间必须有一个空格
  • 常见的配置文件以及其含义
    • cluster.name: 集群名称
    • node.name 节点名称
    • path.data: /path/to/data es的数据存储目录
    • path.logs: /path/to/logs es的日志存储目录
    • bootstrap.memory_lock: true 锁定物理内存地址,防止elasticsearch内存被交换出去,也就是避免es使用swap交换分区中的内存
    • network.host: 192.168.0.1 为es设置ip绑定
    • http.port: 9200 为es设置自定义端口,默认是9200
    • discovery.zen.ping.unicast.hosts: [“host1”, “host2”] 当启动新节点时,通过这个ip列表进行节点发现,组建集群
    • discovery.zen.minimum_master_nodes: 通过配置这个参数来防止集群脑裂现象 (集群总节点数量/2)+1
    • gateway.recover_after_nodes: 3 一个集群中的N个节点启动后,才允许进行数据恢复处理,默认是1
    • action.destructive_requires_name: true 设置是否可以通过正则或者_all删除或者关闭索引库

核心概念

  • cluster

    • 代表的是一个集群,集群中有很多节点,其中有一个主节点,这个主节点通过选举产生,主从节点时对于集群内部而言的。es有一个概念叫去中心化,就是说没有中心节点,这个是对于外部来说的,在外部来看,集群就是一个整体,我们两节集群中的任何一个节点与集群通信跟直接与集群通信是等价的。
    • 主节点的主要职责就是负责管理集群的状态,包括管理分片以及副本的状态,以及节点的删除、新节点的发现等
    • 注意:主节点不负责对进群的增删改查处理,只负责管理集群状态
  • shards

    • 代表的是索引分片,ES将一个完整的索引分成多个分片,这样的好处是可以把一个大的索引分成多个分片后分布到不同的节点上,构成分布式搜索。提高性能和吞吐量

    • 分片的的数量只能在创建索引库的时候指定,索引库创建以后不可以更改

    • 索引库默认是5个分片 每个分片最多存储2,147,483,519条数据

    • 1
      curl -H "Content-Type: application/json" -XPUT 'localhost:9200/test/' -d'{"settings":{"number_of_shards":3}}'
  • replicas

    • 代表的是分片的副本,es给分片设置副本是为了提高系统的容错性,当某个节点的某个分片损坏或者丢失了可以从副本中恢复。

    • 提高es的查询效率,es会自动搜索并请求进行负载均衡

    • 默认每个分区只有一个副本,主副本不会存在于一个节点之上,副本数量可以在创建索引库的时候进行设置吧

    • 1
      curl -XPUT 'localhost:9200/test/' -d'{"settings":{"number_of_replicas":2}}'
  • recovery

    • 代表数据的恢复或者数据的重新分布
    • es在所有节点的加入或者退出后会根据机器的负载对索引分片进行重新分配,挂掉的节点重启时也会进行数据恢复

ElasticsearchJavaAPI操作

使用Java对ES进行操作

  • 添加maven依赖

    • 可以maven仓库中寻找适合你的版本

    • 1
      2
      3
      4
      5
      <dependency>
      <groupId>org.elasticsearch.client</groupId>
      <artifactId>transport</artifactId>
      <version>6.4.3</version>
      </dependency>
  • Java中对ES的简单增删改查操作

    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      package EsTest;

      import org.elasticsearch.action.delete.DeleteResponse;
      import org.elasticsearch.action.get.GetResponse;
      import org.elasticsearch.action.index.IndexResponse;
      import org.elasticsearch.action.update.UpdateResponse;
      import org.elasticsearch.client.transport.TransportClient;
      import org.elasticsearch.common.settings.Settings;
      import org.elasticsearch.common.transport.TransportAddress;
      import org.elasticsearch.common.xcontent.XContentType;
      import org.elasticsearch.transport.client.PreBuiltTransportClient;

      import java.net.InetAddress;
      import java.util.HashMap;
      /**
      * Es简单操作测试
      */
      public class EsDemo1 {
      public static void main(String[] args) throws Exception{
      //给集群添加自动嗅探的功能
      Settings settings = Settings.builder()
      .put("cluster.name", "elasticsearch") //集群名称
      .put("client.transport.sniff", true) //开启自动嗅探功能,可以自动识别集群内的其他节点信息
      .build();
      //创建连接
      TransportClient client = new PreBuiltTransportClient(Settings.EMPTY)
      //可添加多个节点
      //.addTransportAddress(new TransportAddress(InetAddress.getByName("hadoop100"), 9300))
      .addTransportAddress(new TransportAddress(InetAddress.getByName("hadoop110"), 9300));

      //获取节点的信息
      int size = client.connectedNodes().size();
      //System.out.println(size);
      String index = "test";
      String type = "emp";
      //添加数据 使用json字符串
      String json = "{\"name\":\"jack\",\"age\":10}";
      IndexResponse res = client.prepareIndex(index, type, "1")
      .setSource(json, XContentType.JSON).get();
      //System.out.println(res.toString());
      //添加数据 使用map结构
      HashMap<String, Object> map = new HashMap<>();
      map.put("name","zs");
      map.put("age",21);
      IndexResponse res2 = client.prepareIndex(index, type, "101")
      .setSource(map)
      .execute()
      .actionGet();
      //更新操作 update
      UpdateResponse updateResponse = client.prepareUpdate(index, type, "101").setDoc("{\"age\":18}", XContentType.JSON).get();
      //根据ID进行数据查询
      GetResponse get1 = client.prepareGet(index, type, "101").get();
      System.out.println(get1.getSourceAsString());
      //删除操作 delete
      DeleteResponse deleteResponse = client.prepareDelete(index, type, "101").get();
      System.out.println(deleteResponse.toString());

      }

      }

Elasticsearch批量操作的查询类型

Bulk批量查询的Java实现
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    package EsTest;

    import org.elasticsearch.action.bulk.BulkItemResponse;
    import org.elasticsearch.action.bulk.BulkRequestBuilder;
    import org.elasticsearch.action.bulk.BulkResponse;
    import org.elasticsearch.action.delete.DeleteRequest;
    import org.elasticsearch.action.index.IndexRequest;
    import org.elasticsearch.client.transport.TransportClient;
    import org.elasticsearch.common.settings.Settings;
    import org.elasticsearch.common.transport.TransportAddress;
    import org.elasticsearch.transport.client.PreBuiltTransportClient;

    import java.net.InetAddress;

    /**
    * Es简单操作测试
    */
    public class EsDemo2 {
    static String index = "test";
    static String type = "emp";
    public static void main(String[] args) throws Exception{
    Settings settings = Settings.builder()
    .put("cluster.name", "elasticsearch")
    .put("client.transport.sniff", true)
    .build();
    TransportClient client = new PreBuiltTransportClient(Settings.EMPTY)
    .addTransportAddress(new TransportAddress(InetAddress.getByName("hadoop110"), 9300));
    testBulk(client);
    }
    /**
    * bulk批量查询测试
    */
    public static void testBulk(TransportClient client){
    BulkRequestBuilder bulkRequestBuilder = client.prepareBulk();
    //创建请求
    IndexRequest indexRequest = new IndexRequest(index, type)
    .source("{\"name\":\"zs1\",\"age\":25}");
    //删除请求
    DeleteRequest deleteRequest = new DeleteRequest(index, type, "21",,XContentType.JSON);
    //将操作整合到buider中
    bulkRequestBuilder.add(indexRequest);
    bulkRequestBuilder.add(deleteRequest);
    //执行批量操作
    BulkResponse bulkItemResponses = bulkRequestBuilder.get();
    //查看执行过程中失败的信息
    if(bulkItemResponses.hasFailures()){
    BulkItemResponse[] items = bulkItemResponses.getItems();
    for (BulkItemResponse item: items) {
    System.out.println(item.getFailureMessage());
    }
    }else {
    System.out.println("所有bulk指令都执行成功了");
    }

    }

    }

SearchType的详解

  • query and fetch :当客户机向es集群中的某一个节点发送请求时,这个节点会将请求复制到每一个节点上,然后每一个节点会将所请求的数据返回到查询节点上,然后由查询节点返回到客户机上,这样的优点就是速度快,缺点是不准确,客户想要10条数据,集群返回的是10*n条数据,n是集群的节点数

  • query then fetch:当客户机向集群发送请求时,集群中接收请求的节点也会将查询请求发送到每一个节点之上,但是每个节点只返回查询结果的ID等值给主节点,主节点将受到的数据在进行排序取出所需要的条数,然后根据其ID等到相应节点上取的数据,在将数据返回至客户机。优点是可以准确返回需要条数的请求,且结果相对来说准确,缺点是查询速度慢,是es的默认查询类型

  • DFS D是Distributed,F是frequency的缩写,S是Scatter的缩写,整个单词可能是分布式词频率和文档频率散发的缩写

    • dfs简称是初始化散发
    • 官方解释是初始化散发其实就是在进行真正的查询之前,先把各个分片的词频率和文档频率收集一下,然后进行词搜索的时候,各分片依据全局的词频率和文档频率进行搜索和排名。
    • 通俗一点来说就是统计所有节点的搜索排名的算法,总结到一起可以对整个文档进行精确的算法排名
  • dfs query and fetch:就是加了dfs的query and fetch依然是速度快,但是结果条数多

  • dfs query then fetch:执行过程:首先,从各个节点的搜索排序算法即词频率文档频率等,然后根据整合好的算法在每个节点上取出相应数据的ID等信息,在主节点上再次通过该算法获取准确的数据信息,在通过他们的ID等信息去各个节点获取具体数据返回至客户机上。优点是查询准确率高,但是查询速度慢

  • 1566654050267

  • 代码写法

    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      /**
      * Es简单操作测试
      */
      public class EsDemo2 {
      static String index = "test";
      static String type = "emp";
      public static void main(String[] args) throws Exception{
      Settings settings = Settings.builder()
      .put("cluster.name", "elasticsearch")
      .put("client.transport.sniff", true)
      .build();
      TransportClient client = new PreBuiltTransportClient(Settings.EMPTY)
      .addTransportAddress(new TransportAddress(InetAddress.getByName("hadoop110"), 9300));
      //testBulk(client);
      testSeType(client);
      }

      /**
      * 查询类型的测试
      */
      public static void testSeType(TransportClient client){
      SearchResponse searchResponse = client.prepareSearch(index) //索引库信息
      .setQuery(QueryBuilders.matchAllQuery()) //查询规则 所有队列
      .setPreference("_shards:1") //指点分片
      .setSearchType(SearchType.QUERY_THEN_FETCH) //类型可以自己指定
      .get();
      SearchHits hits = searchResponse.getHits();
      //获取总条数
      long totalHits = hits.getTotalHits();
      System.out.println("数据的总条数"+totalHits);
      //打印所有数据内容
      SearchHit[] hits1 = hits.getHits();
      for (SearchHit hit:hits1) {
      System.out.println(hit.getSourceAsString());
      }

      }
      }

Elasticsearch分词详解

es索引建立和搜索过程图解

  • sss

倒排索引介绍

  • 1566654223385
  • 1566654235494
  • 表中的各个单词表示文档意思
    • 单词ID:记录每个单词的编号
    • 单词:单词ID对应的单词
    • 文档频率:单词在几个文档中出现过
    • 倒排列表:单词出现的文档信息以及单词出现位置信息
    • DocID:单词出现的文档的ID
    • TF:单词在该文档出现的次数
    • POS:单词在文档中出现的位置

分词器Analyzer的介绍

  • 分词器就是将数据按以此为单位分开

  • 分词器的作用

    • 是吧文本中的词按照一定的规则进行切分。
    • 分词器所对应的的类是Analyzer是一个抽象类,具体的实现方法要靠他的子类,所以对于不同的语言就可以提供不同的分词器
    • 在创建索引以及搜索的时候都会用到分词器,而且这两个过程所用到的分析器必须是同一种分词器
  • 分词器的工作流程

    • 切分关键词
    • 取出停用词
    • 对于英文字母,将所有字母转换为小写
  • 停用词的介绍

    • 有些词在文本中出现的概率很高但是对于文本所携带的信息并没有什么影响
    • 英文中的
    • 中文的
    • 文本经过分词的过程以后,这种停用词一般都会被过滤掉,不会被索引
    • 如果搜索的词含有停用词一本也会被过滤掉
    • 过滤掉停用词可以加快建立索引,减小索引库的文件的大小
  • 几个重要的分词器介绍

    • 分词器 分词方式
      StandardAnalyzer 单词分词器
      ChineseAnalyzer 单字分词器
      CJKAnalyzer 二分法分词器
      IKAnalyzer 词库分词器
    • 单字分词以及单词分词的意思是一样的

      • “我们是中国人”效果:“我”“们”“是”“中”“国”“人”
    • 二分法分词器:按两个字的方式分词

      • “我们是中国人”,效果:“我们”、“们是”、“是中”、“中国”、“国人”
    • 词库分词器

      • 按某种算法造词,然后将词存入到词库,把搜索内容匹配到词库的词然后进行拆分。

Elasticsearch分词插件介绍以及使用es-ik

  • 官方默认的分词插件对中文的支持不是很好,所以我们需要采用第三方的词库来进行分词,IK就是一个分成不错的分词工具
  • 下载地址
  • 将下载好的文件放在ES_HOME/plugins/ik目录下解压
  • 解压后就可以使用
  • 自己添加词库
    • 进入到config文件中
    • 创建一个自己存放自己词库的文件夹
    • 在文件夹中创建dic文件将自己的词库内容放到所创建的文件中
    • 修改IKAnalyzer.cfg.xml文件信息
    • 将自己创建的词库加进去
    • 重启es就可以使用自己创建的词库了
    • 1566655870803
  • 实现热词的自动更新不需要重启es
    • 在一台服务器上部署一个Tomcat
    • 在Tomcat中的webapp/ROOT 创建hot.doc热词词库
    • 通过访问网络端口确定这个热词库可以访问
    • 1566656094187
    • 修改IK的配置
    • 重启es之后就可以在hot.dic文件中动态添加热词,IK会定时从端口中访问该文件然后进行更新热词

Elasticsearch查询详解

查询Query

  • 代码

    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      public class EsDemo2 {
      static String index = "test";
      static String type = "emp";
      public static void main(String[] args) throws Exception{
      Settings settings = Settings.builder()
      .put("cluster.name", "elasticsearch")
      .put("client.transport.sniff", true)
      .build();
      TransportClient client = new PreBuiltTransportClient(Settings.EMPTY)
      .addTransportAddress(new TransportAddress(InetAddress.getByName("hadoop110"), 9300));
      testSearch(client);
      }
      public static void testSearch(TransportClient client){
      SearchResponse searchResponse = client.prepareSearch(index)
      .setQuery(QueryBuilders.< !-- matchAllQuery() 具体的查询方法 -- >)
      .get();
      SearchHits hits = searchResponse.getHits();
      //获取总条数
      long totalHits = hits.getTotalHits();
      System.out.println("数据的总条数"+totalHits);
      //打印所有数据内容
      SearchHit[] hits1 = hits.getHits();
      for (SearchHit hit:hits1) {
      System.out.println(hit.getSourceAsString());
      }
      }
  • matchAllQuery() 查询所有数据

    • 1
      2
      3
      4
      5
      6
      7
      8
      结果:
      数据的总条数6
      {"name":"jessic","age":18}
      {"name":"zs","age":16}
      {"name":"jack","age":19}
      {"name":"lili","age":16}
      {"name":"zs","age":15}
      {"name":"tom","age":19}
  • matchQuery((“name”,”zs”)) 根据指定列进行模糊查询 不支持通配符

    • 1
      2
      3
      数据的总条数2
      {"name":"zs","age":16}
      {"name":"zs","age":15}
  • multiMatchQuery(“zs”,”name”,”city”) 在多个列中进行模糊查询 查询的列不存在不会报错

    • 1
      2
      3
      数据的总条数2
      {"name":"zs","age":16}
      {"name":"zs","age":15}
  • queryStringQuery(“name:z*”) Lucene提供的方法支持对某一列查询的时候使用通配符

    • 1
      2
      3
      数据的总条数2
      {"name":"zs","age":16}
      {"name":"zs","age":15}
  • boolQuery()

    .should(QueryBuilders.matchQuery(“name”,”zs”).boost(10.0f)) .should(QueryBuilders.matchQuery(“age”,19).boost(1.0f))

    根据不同的条件进行多次查询 可以根据boost值来设置两条语句的结果先后顺序

    • 1
      2
      3
      4
      5
      数据的总条数4
      {"name":"zs","age":16}
      {"name":"zs","age":15}
      {"name":"jack","age":19}
      {"name":"tom","age":19}
  • termQuery(“name”,”abc xyz”) 查询的时候不会进行分词的精确查询

    • 1
      数据的总条数0
    • 在默认情况之下es会将所有词进行分词索引,这是你试试用及精确查询时查不到的

    • 解决方案

      • 在创建索引的时候将不需要进行分词的特殊索引指定不分词

      • 根据Lucene提供的方法直接查询可以对已经分词的索引进行精确查询

      • queryStringQuery(“name:"abc xyz"“)

      • 1
        2
        数据的总条数1
        {"name":"abc xyz","age":15}
  • matchQuery(“name”,”abc xyz”).operator(Operator.AND) 也可以对已经分词的索引进行精确查询

    • 1
      2
      数据的总条数1
      {"name":"abc xyz","age":15}

其他查询

  • from、size 分页

    • 1
      2
      3
      4
      5
      .setFrom(2)
      .setSize(3)
      {"name":"jack","age":19}
      {"name":"lili","age":16}
      {"name":"abc xyz","age":15}
  • sort 排序

    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      .setQuery(QueryBuilders.matchAllQuery()) //取出所有数据
      .addSort("age", SortOrder.DESC) //按照年龄降序排序

      {"name":"jack","age":19}
      {"name":"tom","age":19}
      {"name":"jessic","age":18}
      {"name":"zs","age":16}
      {"name":"lili","age":16}
      {"name":"abc xyz","age":15}
  • filter 过滤

    • 1
      2
      3
      4
      5
      6
      7
      .setPostFilter(QueryBuilders.rangeQuery("age").from("16").to(20))
      过滤出来年龄在1620之间的
      {"name":"jessic","age":18}
      {"name":"zs","age":16}
      {"name":"jack","age":19}
      {"name":"lili","age":16}
      {"name":"tom","age":19}
  • highlight 高亮 将搜索出的结果加上高亮的效果

  • 按查询匹配度排序

    • .setExplain(true)

两个简单练习

  • 聚合分组求count

    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      /**
      * 统计测试
      * 聚合分组求count
      */
      public static void testAggregation(TransportClient client){
      SearchResponse searchResponse = client.prepareSearch(index)
      //.setTypes(type)
      .setQuery(QueryBuilders.matchAllQuery())
      .addAggregation(AggregationBuilders.terms("term_age").field("age"))
      .get();
      Terms term_age = searchResponse.getAggregations().get("term_age");
      List<? extends Terms.Bucket> buckets = term_age.getBuckets();
      for (Terms.Bucket bk:buckets) {
      System.out.println(bk.getKey()+"----------"+bk.getDocCount());
      }
      }
  • 聚合分组求sum

    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      /**
      * 统计测试
      * 聚合分组求sum
      */
      public static void testAggregation2(TransportClient client){
      SearchResponse searchResponse = client.prepareSearch(index)
      .setQuery(QueryBuilders.matchAllQuery())
      .addAggregation(AggregationBuilders.terms("term_name").field("name.keyword") //name是text类型不支持分组,所以取他的keyword
      .subAggregation(AggregationBuilders.sum("sum_score").field("score")))
      .get();
      Terms term_name = searchResponse.getAggregations().get("term_name");
      List<? extends Terms.Bucket> buckets = term_name.getBuckets();
      for (Terms.Bucket bk:buckets) {
      Sum sumScore = bk.getAggregations().get("sum_score");
      System.out.println(bk.getKey()+"----------"+sumScore.getValue());
      }
      }

Elasticsearch中的setting以及mapping详解

  • setting是修改索引库默认的配置

    • 查看页面的setting信息

    • 修改已经存在的索引库信息

      • 1
        curl -H "Content-Type: application/json" -XPUT 'localhost:9200/test/_settings' -d'{"index":{"number_of_replicas":1}}'
  • 修改不存在的索引库的信息

    • 1
      curl -H "Content-Type: application/json" -XPUT 'localhost:9200/test1/' -d'{"settings":{"number_of_shards":3,"number_of_replicas":0}}'
  • mapping 是对索引库中的索引的名称以及数据类型进行定义,类似于MySQL的表名以及表的结构信息。但是es的mapping比较灵活,可以动态识别各字段的信息,一般不需要自定义mapping

    • 查看索引库mapping信息

      • 1
        curl -XGET http://localhost:9200/test/emp/_mapping?pretty
    • 操作已经存在的索引 指定分词器

      • 1
        curl -H "Content-Type: application/json" -XPOST http://localhost:9200/test/emp/_mapping -d'{"properties":{"name":{"type":"text","analyzer": "ik_max_word"}}}'
  • 操作不存在的索引

    • 1
      curl -H "Content-Type: application/json" -XPUT 'localhost:9200/test2' -d'{"mappings":{"emp":{"properties":{"name":{"type":"text","analyzer": "ik_max_word"}}}}}'

Elasticsearch的分片查询方式

  • 默认的是randomize across shards 表示随机选取,即随机从分片中取数据
  • _local :表示执行查询操作的时候回优先在本地节点中的分片中进行查询,没有的话在去其他节点
  • _only_local:表示只在本地分片中查询
  • _primary:表示只在主分片中查询
  • _primary_first:表示优先在主分片中查询,如果主分片出现问题数据丢失或者其他就会去副分片中查询
  • _replica_first:表示优先在副分片上查询,有问题了再去主分片查询
  • _only_node:在指定ID的节点上查询,只有该节点上有相关分片就回进行查询,可能导致查询结果不够完整
  • _only_nodes:指定ID的节点是多个
  • _prefer_node:优先在指定ID的节点查询 查不到再去其他节点
  • _shards:查询指定分片的信息 可以实现急速查询 但需要指定索引所在分片的信息

博客内容遵循 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议

本站使用 Blog Zhao 作为主题 , 总访问量为 次 。
载入天数...载入时分秒...