Elasticsearch 6.0におけるJava APIの活用
1:Java APIを使用したElasticsearchクライアントの作成
package com.example.elasticsearch.client;
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;
public class EsConnectionManager {
private static TransportClient esClient;
public TransportClient getEsConnection() {
try {
Settings configuration = Settings.builder()
.put("cluster.name", "production-cluster")
.put("client.transport.ignore_cluster_name", true)
.build();
// クライアントの作成
esClient = new PreBuiltTransportClient(configuration)
.addTransportAddress(new TransportAddress(InetAddress.getByName("localhost"), 9300));
return esClient;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
2:クライアントを使用したインデックスの作成とIKアナライザの指定
package com.example.elasticsearch.operations;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.admin.indices.analyze.AnalyzeRequestBuilder;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.IndicesAdminClient;
import org.elasticsearch.client.Requests;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import java.io.IOException;
import java.net.InetAddress;
import java.util.Date;
import java.util.Map;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
public class EsIndexHandler {
private TransportClient esClient;
public EsIndexHandler() {
this.esClient = new EsConnectionManager().getEsConnection();
}
// インデックスの作成とIKアナライザの指定
public void setupIndexWithAnalyzer() throws IOException {
// マッピングの作成
XContentBuilder mappingDefinition = XContentFactory.jsonBuilder()
.startObject()
.startObject("properties")
.startObject("title").field("type", "text").field("analyzer", "ik_smart").endObject()
.startObject("content").field("type", "text").field("analyzer", "ik_max_word").endObject()
.endObject()
.endObject();
// インデックスとマッピングの設定
PutMappingRequest mappingRequest = Requests.putMappingRequest("articles").type("document").source(mappingDefinition);
// インデックスの作成
esClient.admin().indices().prepareCreate("articles").execute().actionGet();
// マッピングの適用
esClient.admin().indices().putMapping(mappingRequest).actionGet();
}
}
これでインデックスが作成され、マッピングが設定されます。
3:作成したインデックスへのデータ追加(IDは重複不可)
public void addDocumentToIndex() throws IOException {
IndexResponse response = esClient.prepareIndex("articles", "document", "doc1")
.setSource(jsonBuilder()
.startObject()
.field("title", "Elasticsearch入門")
.field("content", "Elasticsearchは高性能な検索エンジンです")
.endObject()
).get();
}
Postmanを使用してインデックスをクエリできます:
4:インデックスの更新(IDが同じ場合は上書き)
public void updateExistingDocument() throws IOException {
UpdateResponse response = esClient.update(new UpdateRequest("articles", "document", "doc1")
.doc(XContentFactory.jsonBuilder()
.startObject()
.field("title", "Elasticsearch完全ガイド")
.field("content", "Elasticsearchは分散型のオープンソース検索エンジンであり、大量のデータを高速に検索できます")
.endObject()
)).get();
}
Postmanを使用して更新後のインデックス内容を確認できます
5:インデックスのクエリ(アナライザによる分词処理)
contentフィールドのクエリ:
クエリ結果:
titleフィールドのクエリ:
クエリ結果:
6:インデックスへの追加データ投入
public void addSecondDocument() throws IOException {
IndexResponse response = esClient.prepareIndex("articles", "document", "doc2")
.setSource(jsonBuilder()
.startObject()
.field("title", "検索エンジン技術")
.field("content", "検索エンジン技術は現代の情報検索において不可欠です")
.endObject()
).get();
}
contentフィールドのクエリ:
結果:2件のドキュメントがヒットします。クエリ内容「Elasticsearch」が細かく分割され、「検索」という語句が両方のドキュメントに含まれるためです。
titleフィールドのクエリ:
クエリ結果:1件のみヒットします。titleフィールドでは粗粒度のアナライザが使用されるためです。
7:Search APIの操作:
public void performSearchOperations() {<br></br> // titleフィールドでの検索<br></br> SearchResponse titleSearch = esClient.prepareSearch("articles")<br></br> .setTypes("document")<br></br> .setSearchType(SearchType.QUERY_THEN_FETCH)<br></br> .setQuery(QueryBuilders.matchQuery("title", "Elasticsearch"))<br></br> .setFrom(0).setSize(10).setExplain(true)<br></br> .get();<br></br> <br></br> long titleHits = titleSearch.getHits().totalHits;<br></br> System.out.println("titleでのヒット数: " + titleHits);<br></br> <br></br> // contentフィールドでの検索<br></br> SearchResponse contentSearch = esClient.prepareSearch("articles")<br></br> .setTypes("document")<br></br> .setSearchType(SearchType.QUERY_THEN_FETCH)<br></br> .setQuery(QueryBuilders.matchQuery("content", "検索"))<br></br> .setFrom(0).setSize(10).setExplain(true)<br></br> .get();<br></br> <br></br> long contentHits = contentSearch.getHits().totalHits;<br></br> System.out.println("contentでのヒット数: " + contentHits);<br></br> }
8:Get APIの操作:
public void retrieveDocument() {
GetResponse response = esClient.prepareGet("articles", "document", "doc1").get();
Map<String, Object> documentSource = response.getSource();
for (Map.Entry<String, Object> entry : documentSource.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
}
9:Bulk APIによる一括データ追加
/**
* 一括でインデックスを作成しデータを追加
*/
public void bulkIndexDocuments() throws IOException {
BulkRequestBuilder bulkOperation = esClient.prepareBulk();
// 最初のドキュメント
bulkOperation.add(esClient.prepareIndex("articles", "document", "doc3")
.setSource(jsonBuilder()
.startObject()
.field("title", "全文検索システム")
.field("postDate", new Date())
.field("content", "全文検索システムはドキュメント全体を対象に検索を行います")
.endObject()
)
);
// 2番目のドキュメント
bulkOperation.add(esClient.prepareIndex("articles", "document", "doc4")
.setSource(jsonBuilder()
.startObject()
.field("title", "分散アーキテクチャ")
.field("postDate", new Date())
.field("content", "Elasticsearchは分散アーキテクチャを採用しています")
.endObject()
)
);
BulkResponse bulkResponse = bulkOperation.get();
if (bulkResponse.hasFailures()) {
// エラー処理
System.out.println("Bulk操作に失敗しました: " + bulkResponse.buildFailureMessage());
} else {
System.out.println("Bulk操作が成功しました");
}
}
10:検索結果のJSON形式での返却
/**
* 商品検索機能
*/
public JSONObject searchProducts(String keyword) {
SearchResponse searchResult = esClient.prepareSearch("products", "catalog")
.setTypes("item")
.setSearchType(SearchType.QUERY_THEN_FETCH)
.setQuery(QueryBuilders.matchQuery("productName", keyword))
.setFrom(0).setSize(20).setExplain(true)
.get();
SearchHit[] matchedItems = searchResult.getHits().getHits();
JSONObject resultJson = new JSONObject();
for (int i = 0; i < matchedItems.length; i++) {
String documentJson = matchedItems[i].getSourceAsString();
resultJson.put("item_" + i, documentJson);
}
return resultJson;
}
Elasticsearchの高速性の理由: https://www.elastic.co/jp/blog/why-is-elasticsearch-so-fast
Java API公式ドキュメント: https://www.elastic.co/guide/en/elasticsearch/client/java-api/6.0/index.html