ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。

     我们最熟悉的百度搜索便是应用了Elasticsearch,es提供了高亮、聚合统计、分组查询等。它在分布式部署下提供了强大的索引能力,使其具有极强的实时性,大量应用于项目开发中各种实时的应用场景。它有以下优点:

1.分布式文件存储,而且把每个字段编入索引,使其查询高效速度快

2.扩展性强,便于横向扩展,可处理PB级数据

3.利用其分片和master选举,使其具有较强的容错机制

简单说下linux下部署es集群:

        一般只要修改config下的elasticsearch.yml配置文件即可

# https://www.elastic.co/guide/en/elasticsearch/reference/index.html
#
# ---------------------------------- Cluster -----------------------------------
#
# Use a descriptive name for your cluster:
#
#cluster.name: my-application
cluster.name: cluster1
# ------------------------------------ Node ------------------------------------
#
# Use a descriptive name for the node:
#
#node.name: node-1
node.name: node1
# Add custom attributes to the node:
#
#node.attr.rack: r1
#
# ----------------------------------- Paths ------------------------------------
#
# Path to directory where to store the data (separate multiple locations by comma):
#
#path.data: /path/to/data
path.data: /data/es/data
# Path to log files:
#
#path.logs: /path/to/logs
path.logs: /data/es/logs
# ----------------------------------- Memory -----------------------------------
#
# Lock the memory on startup:
#
#bootstrap.memory_lock: true
bootstrap.memory_lock: true
# Make sure that the heap size is set to about half the memory available
# on the system and that the owner of the process is allowed to use this
# limit.
#
# Elasticsearch performs poorly when the system is swapping the memory.
#
# ---------------------------------- Network -----------------------------------
#
# Set the bind address to a specific IP (IPv4 or IPv6):
#
#network.host: 192.168.0.1
network.host: 0.0.0.0
# Set a custom port for HTTP:
#
#http.port: 9200
#
# For more information, consult the network module documentation.
#
# --------------------------------- Discovery ----------------------------------
#
# Pass an initial list of hosts to perform discovery when new node is started:
# The default list of hosts is ["127.0.0.1", "[::1]"]
#
#discovery.zen.ping.unicast.hosts: ["host1", "host2"]
discovery.zen.ping.unicast.hosts: [ "192.168.xx.xxx", "192.168.xx.xxx", "192.168.xx.xxx"]

cluster.name:  集群名称,每个es节点必须拥有相同的集群名称

node.name:节点名称

network.host:节点所在服务器的ip地址,如果要在浏览器直接访问该节点可改为0.0.0.0

http.port:服务端端口,默认9200

discovery.zen.ping.unicast.hosts:集群内所有节点,可用ip也可用节点名称

如果需要增加jvm的内存,可修改config下的jvm.options

接下来重点讲解java中如何连接elasticsearch集群和创建索引及type,且自定义它的结构,本文不会展示全部代码,因为代码量多,主要讲解一个封装思路,后面讲到springboot我会把代码发布到gitHub

创建一个ElasticsearchServiceImpl实现类

1.启动初始化es

 

@PostConstruct   //改注解为启动服务便初始化运行该方法
    private void init() {
        getHosts();     //加入所有节点
        if (connectWhenStartup) {    //此为是否要启动便连接es,可自行增加配置文件设置
            connect();
        }
        createBuiltInIndices();  //创建索引
    }

我们来看看创建索引这个方法

 private void createBuiltInIndices() {
        String indexName;
        BaseIndexModel model;   //实体类基类
        for (Class clazz : DataModelUtils.getBuiltInClazzes()) {  
            List<DataItem> dataItems = DataModelUtils.getModelDataItems(clazz);
            try {
                model = (BaseIndexModel) clazz.newInstance();  //通过反射实例化
                indexName = model.getIndexName();
                if (!indexExists(indexName)) {  //判断索引是否存在,不存在则创建索引
                    createIndexNType(indexName, dataItems);  //创建索引
                }
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        }
    }

大家看到这个地方可能有点迷糊,BaseIndexModel是啥,BaseIndexModel是我自定义的一个基类,所有要存入es的实体都继承这个基类,然后通过自行创建的配置文件properties:

people=cn.gzis.gxpt.core.biz.model.People
student=cn.gzis.gxpt.core.biz.enterprise.model.Student

 DataModelUtils.getBuiltInClazzes()方法便是我自己编写的一个处理properties的静态方法,然后通过反射给每一个实体实例化,且基类中有一个getIndexName()方法,用来获取properties中的key,用key作为该实体在es中的索引名。

DataModelUtils.getModelDataItems(clazz)方法是通过反射获取该类所有字段,

最后把字段和索引名传入createIndexNType()方法中,用于创建索引。

 

接下来我们来看看创建type这个方法

 public boolean createType(String indexName, Collection<DataItem> dataItems) {
        if (StringUtils.isBlank(indexName) || null == dataItems || dataItems.isEmpty()) {
            return false;
        }
        boolean flag;
        logger.debug("准备创建Type...");
        try {
            XContentBuilder xcb = XContentFactory.jsonBuilder().startObject().startObject(ELASTICSEARCH_TYPE).startObject("properties"); //创建json结构
            for (DataItem dataItem : dataItems) {   //遍历数据项,需要有一个数据项的实体
                xcb = xcb.startObject(dataItem.getEname())
                        .field("type", "text")
                        .field("store", "yes")
                        .field("fielddata", "true")
                        .startObject("fields")
                        .startObject("keyword")
                        .field("type", "keyword").field("ignore_above", 256)
                        .endObject();
                if (DataItemType.NUMBER.equals(dataItem.getType())) {  //根据类型创建mapping数据结构
                    xcb = xcb.startObject("number").field("type", "double").endObject();
                }
//                if (DataItemType.DATE.equals(dataItem.getType())) {
//                    xcb = xcb.startObject("date").field("type", "date").field("format", "yyyy-MM-dd").endObject();
//                }
                if (DataItemType.DATETIME.equals(dataItem.getType())) {
                    xcb = xcb.startObject("date").field("type", "date").field("format", "yyyy-MM-dd HH:mm:ss || yyyy-MM-dd HH:mm:ss.SSS || yyyy-MM-dd || yyyyMM").endObject();
                }
                xcb.endObject().endObject();
            }
            logger.debug("创建Type...");
            flag = getAdminClient().indices().preparePutMapping(indexName).setType(ELASTICSEARCH_TYPE).setSource(xcb.endObject().endObject().endObject()).get().isAcknowledged();  //通过es api创建索引
            logger.debug(flag ? "创建Type成功!" : "创建Type失败!");
            return flag;
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
            return false;
        }
    }

在这个地方,我使用了es的xContent去创建一个Mappng映射的json,然后遍历每个实体的数据项(就是字段),根据字段类型创建索引类型。

到了最后一步利用es的java api,通过setSource把mapping结构传递进去,我们的索引就基本创建成功了!

最后说一句,elasticsearch广泛运用于大数据实时查询中,是学大数据必不可少的一门框架技术,特别是es的聚合统计有利于数据计算和分析,希望大家可以多多了解交流

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐