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