大数据015——Elasticsearch深入

1. Elasticsearch 核心概念

1.1 cluster

代表一个集群,集群中有多个节点,其中有一个为主节点,这个主节点是可以通过选举产生的,主从节点是对于集群内部来说的。es的一个重要概念就是去中心化,字面上理解就是无中心节点,这是对于集群外部来说的,因为从外部来看es集群,在逻辑上是个整体,你与任何一 个节点的通信和与整个es集群通信是等价的。

  • 主节点的职责是负责管理集群状态,包括管理分片的状态和副本的状态,以及节点的发现和删除。
  • 只需要在同一个网段之内启动多个es节点,就可以自动组成一个集群。
  • 默认情况下es会自动发现同一网段内的节点,自动组成集群。
  • 集群状态查看 :http://node01:9200/_cluster/health?pretty

1.2 shards

代表索引分片,es可以把一个完整的索引分成多个分片,这样的好处是可以把一个大的索引拆分成多个,分布到不同的节点上。构成分布式搜索。分片的数量只能在索引创建前指定,并且索引创建后不能更改。

  • 可以在创建索引库的时候指定

    – curl -XPUT ‘node01/test1/’ -d’{“settings”:{“number_of_shards”:3}}’

在这里插入图片描述

  • 默认是一个索引库有5个分片

    – number_of_shards: 5

1.3 replicas

代表索引副本,es可以给索引设置副本,副本的作用一是提高系统的容错性,当某个节点某个分片损坏或丢失时可以从副本中恢复。二是提高es的查询效率,es会自动对搜索请求进行负载均衡。

  • 可以在创建索引库的时候指定

    – curl -XPUT ‘node01:9200/test2/’ -d’{“settings”:{“number_of_replicas”:2}}’

在这里插入图片描述

  • 默认是一个分片有1个副本 (总共有两片)

    – number_of_replicas: 1

1.4 recovery

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

1.5 gateway

代表es索引的持久化存储方式,es默认是先把索引存放到内存中,当内存满了时再持久化到硬盘。当这个es集群关闭再重新启动时就会从gateway中读取索引数据。es支持多种类型的gateway,有本地文件系统(默认),分布式文件系统,Hadoop的HDFS和amazon的 s3云存储服务。

如果需要将数据落地到hadoop的hdfs需要先安装插件 elasticsearch/elasticsearch-hadoop 。

1.6 discovery.zen

代表es的自动发 现节点机制,es是一个基于p2p的系统,它先通过广播寻找存在的节点,再通过多播协议来进行节点之间的通信,同时也支持点对点的交互。

如果是不同网段的节点如何组成es集群 :

  • 禁用自动发现机制

    – discovery.zen.ping.multicast.enabled: false

  • 设置新节点被启动时能够发现的主节点列表

    – discovery.zen.ping.unicast.hosts: [“192.168.1.191", " 192.168.1.192"]

1.7 Transport

代表es内部节点或集群与客户端的交互方式,默认内部是使用tcp协议进行交互,同时它支持http协议(json格式)、thrift、servlet、 memcached、zeroMQ等的传输协议(通过插件方式集成)。

2. Elasticsearch中的settings和mappings

2.1 settings 索引库默认配置

例如:分片数量,副本数量;

  • 查询默认配置:
[root@node01 ~]# curl -XGET http://node01:9200/mydoc/_settings?pretty
{
  "mydoc" : {
    "settings" : {
      "index" : {
        "creation_date" : "1548425875227",
        "number_of_shards" : "5",
        "number_of_replicas" : "1",
        "uuid" : "8gT7jufeSp6q6789LRuBNA",
        "version" : {
          "created" : "2040599"
        }
      }
    }
  }
}

  • 设置分片、副本数量(在创建的时候设置):
curl -XPUT http://node01:9200/helloword/ -d '{
"settings":
    {
        "number_of_shards":3,
        "number_of_replicas":2
    }
}'

2.2 Mapping 索引库默认配置

Mapping 是对索引库中索引的字段名称及其数据类型进行定义,类似于关系数据库中表建立时要定义字段名及其数据类型那样,(和solr中的schme类似)不过es 的mapping比数据库灵活很多,它可以动态添加字段。一般不需要要指定 mapping都可以,因为es会自动根据数据格式定义它的类型,如果你需要对某些字段添加特殊属性(如:定义使用其它分词器、是否分词、是否存储等),就必须手动添加mapping。

  • 查询索引库的mapping信息

    curl -XGET http://node01:9200/mydoc/employee/_mapping?pretty

    [root@node01 ik]# curl -XGET http://node01:9200/mydoc/employee/_mapping?pretty
    {
      "mydoc" : {
        "mappings" : {
          "employee" : {
            "properties" : {
              "about" : {
                "type" : "string"
              },
              "address" : {
                "type" : "string"
              },
              "age" : {
                "type" : "long"
              },
              "first_name" : {
                "type" : "string"
              },
              "last_name" : {
                "type" : "string"
              }
            }
          }
        }
      }
    }
    
  • mappings修改字段相关属性

    – 例如:字段类型,使用哪种分词工具。

3. Elasticsearch 的 java API

3.1 参数设置

@Before
public void client() throws UnknownHostException, IllegalAccessException, InstantiationException {
    Map<String, String> map = new HashMap<String, String>();
    // 1. 设置集群名称,默认是elasticsearch
    map.put("cluster.name", "myes");
    Settings.Builder settings = Settings.builder().put(map);
	// 2. 通过TransportClient这个接口,我们可以不启动节点就可以和es集群进行通信
    client = TransportClient.builder().settings(settings).build();
	// 3. 设置es集群机器的ip地址及通讯端口
    client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("node01"), 9300));
    client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("node02"), 9300));
    client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("node03"), 9300));

}

3.2 创建索引库

    /**
     * 创建索引库
     */
    @Test
    public void createIndexBase() {
    	// 1. 设置索引库名称
        IndicesExistsResponse actionGet = client.admin().indices().prepareExists("test").execute().actionGet();
		// 2. 判断是否存在
        if (actionGet.isExists()) {
            System.out.println("test索引库已存在。。");

            client.admin().indices().prepareDelete("test").execute();
        }
        Map<String, String> map = new HashMap<>();
		// 3. 设置索引库的副本数于分片数
        map.put("number_of_replicas", "2");
        map.put("number_of_shards", "3");
		// 4. 执行创建
        client.admin().indices().prepareCreate("test").setSettings(map).execute();
           
    }

3.3 添加索引

    /**
     * 添加索引
     */
    @Test
    public void addIndex() {
        // 1. 创建map形式的数据
        HashMap<String, Object> hashMap = new HashMap<String, Object>();
        hashMap.put("name", "bin");
        hashMap.put("age", 28);
        hashMap.put("gender", "male");
        hashMap.put("describe", "lyp is good");

        // 2. 这里指定 id 添加索引
//        IndexResponse response = client.prepareIndex("test", "employee", "79").setSource(hashMap).execute()
//                .actionGet();
		// 3. 这里未指定 id ,则系统会随机生成id
        IndexResponse response1 = client.prepareIndex("test", "employee").setSource(hashMap).execute().actionGet();
        
        System.out.println(response1.getId());//打印随机生成的id
    }

输出:

gender ->male
name ->bin
describe ->lyp is good
age ->28

3.4 更新索引

    /**
     * 更新
     *
     * @throws Exception
     */
    @Test
    public void update() throws Exception {
        UpdateRequest updateRequest = new UpdateRequest();
        updateRequest.index("test");
        updateRequest.type("employee");
        updateRequest.id("79");
        Map<String, Object> map = new HashMap<>();
        // 对没有的字段添加, 对已有的字段更新
        map.put("age", "25");
        map.put("date", "2018-01-01");
        updateRequest.doc(map);
        
//        updateRequest.doc(
//                XContentFactory.jsonBuilder()
//                        .startObject()
//                        // 对没有的字段添加, 对已有的字段更新
//                        .field("age", "26")
//                        .field("city", "shanghai")
//                        .endObject());


        client.update(updateRequest);


    }

3.5 查询索引

    /**
     * 查询
     */
    @Test
    public void search() {
        //指定从test,mydoc索引库里查询

        SearchRequestBuilder builder = client.prepareSearch("test", "mydoc");
        //指定从employee,ikType,blog,这三个type里面查询
        builder.setTypes("employee", "ikType", "blog");
        //设置分页,从第0个开始,返回3个。
        builder.setFrom(0);
        builder.setSize(3);

        String key = "bin";
        //设置从name和content字段里查询
        builder.setQuery(QueryBuilders.multiMatchQuery(key, "name", "content","first_name"));
  
         builder.addSort("age", SortOrder.DESC); //设置排序字段,默认的话会根据相关性打分。
        // builder.setPostFilter(QueryBuilders.rangeQuery("age").from(24).to(28)); 设置过滤
        // 开始查询。
        SearchResponse searchResponse = builder.get();
        //获取查询的返回信息
        SearchHits hits = searchResponse.getHits();

        //一共有多少个符合条件的查询结果
        System.out.println("总共查询到了:" + hits.getTotalHits());

        //获取查询到的结果数组
        SearchHit[] hits2 = hits.getHits();

        for (SearchHit searchHit : hits2) {

            System.out.println("分数:" + searchHit.getScore());

            Map<String, Object> source = searchHit.getSource();
            System.out.println("id ->" + searchHit.getId());
            System.out.println("index -> " + searchHit.index());
            for (String s : source.keySet()) {
                System.out.println(s + "->" + source.get(s));
            }
            System.out.println("--------");
        }

    }

猜你喜欢

转载自blog.csdn.net/sinat_34045444/article/details/86671961