1. 程式人生 > >使用java操作Elasticsearch建立自定義索引

使用java操作Elasticsearch建立自定義索引

      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的聚合統計有利於資料計算和分析,希望大家可以多多瞭解交流