Java Web Application and ElasticSearch (Video)
Join the DZone community and get the full member experience.
Join For FreeToday I am demonstrating the usage of ElasticSearch, which is an open source, distributed and scalable full text search engine and a data analysis tool in a Java web application.
First of all, I want to share with you a video recording. I made this video with the aim of visually reinforcing the issues that I dealt in a series of articles about ElasticSearch.
2.Dependencies
Application: ElasticSearch
Now we can continue where we left off.
Our data will be stored in a database management system in an enterprise application where there is high traffic and where simultaneously incoming requests can be expressed in hundreds or even in thousands. However, routing all these data to the database may pose a bottleneck risk. The main objective in this tutorial is minimizing the database I/O operations, which are most likely to create a bottleneck risk (especially when working with big data) in a web application with a tool like ElasticSearch.
The application (the introduction takes place in the video) with Java API designed for this purpose performs some operations, such as sending the post data to ElasticSearch, getting, searching (full text), as well as updating and deleting operations. ElasticSearch is also functioning as a data store in this application. The hypothetical example that we will follow is about recording the published articles in kodcu.com, which was in the previous articles.
Tools and technologies I used in the sample application:
- ElasticSearch version 0.90.3
- JSF version 2.2
- PrimeFaces version 3.5
- Jetty 7.x Maven Plugin
- Maven version 3.0.4
- JDK version 1.7

<dependency> <groupId>org.glassfish</groupId> <artifactId>javax.faces</artifactId> <version>${jsf.version}</version> </dependency> <dependency> <groupId>org.primefaces</groupId> <artifactId>primefaces</artifactId> <version>${primeFaces.version}</version> </dependency> <dependency> <groupId>org.primefaces.themes</groupId> <artifactId>bootstrap</artifactId> <version>${primeFacesTheme.version}</version> </dependency> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>${commonsFileUpload.version}</version> </dependency> <dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>${elastic.version}</version> </dependency> <dependency> <groupId>jboss</groupId> <artifactId>jboss-j2ee</artifactId> <version>${jbossJ2ee.version}</version> </dependency>3. ClientProvider.java
public class ClientProvider { private static ClientProvider instance = null; private static Object lock = new Object(); private Client client; private Node node; public static ClientProvider instance(){ if(instance == null) { synchronized (lock) { if(null == instance){ instance = new ClientProvider(); } } } return instance; } public void prepareClient(){ node = nodeBuilder().node(); client = node.client(); } public void closeNode(){ if(!node.isClosed()) node.close(); } public Client getClient(){ return client; } public void printThis() { System.out.println(this); } }We will get the client object once again, and we will carry out all operations on ElasticSearch from a client verifier that was encoded by singleton pattern approach, rather than getting again and again before each operation. 4. ElasticSearchSystemEventListener.java
@Override public void processEvent(SystemEvent event) throws AbortProcessingException { if(event instanceof PostConstructApplicationEvent){ /* Preparing the ElasticSearch Client */ System.out.println("*********************************************"); System.out.println("Preparing the ElasticSearch Client"); ClientProvider.instance().prepareClient(); System.out.println("The ElasticSearch Client was prepared"); System.out.println("*********************************************"); } if(event instanceof PreDestroyApplicationEvent){ /* ElasticSearch node is closing */ System.out.println("*********************************************"); System.out.println("ElasticSearch Node is closing"); ClientProvider.instance().closeNode(); System.out.println("ElasticSearch Node was closed"); System.out.println("*********************************************"); } }Because the application has been built with JSF, we used the SystemEventListener implementation, which is the optimal option to create an embedded node when the application arises, request a client from this node, and then close it when the application ends. 5. Listing data in DataTable In order to take full advantage of the functionality provided by the DataTable component of PrimeFaces, documents which were acquired with Search API need to be converted to POJO. This operation is performed manually. It is possible to use the jackson-databind library for this purpose.
public void prepareDocumentList(){ wildCardQuery = ""; ClientProvider.instance().getClient() .admin().indices().prepareRefresh().execute().actionGet(); try { SearchResponse response = ClientProvider.instance().getClient() .prepareSearch(INDEX_NAME) .setTypes(TYPE_NAME) .setQuery(matchAllQuery()) .execute() .actionGet(); articleList.clear(); Article temporary = null; String[] tags = null; if (response != null) { for (SearchHit hit : response.getHits()) { try { tags = hit.getSource().get("tags").toString().split(","); temporary = new Article(Long.parseLong(hit.getSource().get("id").toString()), hit.getSource().get("title").toString(), hit.getSource().get("content").toString(), new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault()).parse(hit.getSource().get("postDate").toString()), hit.getSource().get("author").toString(), tags); } catch (ParseException e) { e.printStackTrace(); } articleList.add(temporary); } } collectionSort(); } catch (IndexMissingException ex){ System.out.println("IndexMissingException: " + ex.toString()); } }6. Registry and Update
public void saveArticle() { Long ID = 1l; try { CountResponse countResponse= ClientProvider.instance().getClient() .prepareCount(INDEX_NAME) .setQuery(termQuery("_type", TYPE_NAME)) .execute().actionGet(); ID += countResponse.getCount(); } catch (IndexMissingException ex){ System.out.println("IndexMissingException: " + ex.toString()); } String[] postTags = tag.split(","); try { if(null == selectArticle) ClientProvider.instance().getClient().prepareIndex(INDEX_NAME, TYPE_NAME, ID.toString()) .setSource(putJsonDocument(ID, article.getTitle(), article.getContent(), article.getPostDate(), postTags, article.getAuthor())).execute().actionGet(); else { Map<String, Object> updateObject = new HashMap<String, Object>(); updateObject.put("title", selectArticle.getTitle()); updateObject.put("content", selectArticle.getContent()); updateObject.put("postDate", selectArticle.getPostDate()); updateObject.put("author", selectArticle.getAuthor()); updateObject.put("tags", postTags); ClientProvider.instance().getClient().prepareUpdate(INDEX_NAME, TYPE_NAME, selectArticle.getId().toString()) .setScript("ctx._source.title=title; ctx._source.content=content; " + "ctx._source.postDate=postDate; ctx._source.author=author; " + "ctx._source.tags=tags") .setScriptParams(updateObject).execute().actionGet(); } } catch (Exception ex){ FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Sorry, an error has occurred", ex.toString())); } prepareDocumentList(); initArticle(); }7. Delete
public void removeArticle(){ try { ClientProvider.instance().getClient().prepareDelete(INDEX_NAME, TYPE_NAME, selectArticle.getId().toString()).execute().actionGet(); } catch (Exception ex){ FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Sorry, an error has occurred", ex.toString())); } prepareDocumentList(); initArticle(); }8. Full text source and wildcard
public void fullTextSearch(){ articleList.clear(); Article temporary = null; String[] tags = null; try { QueryBuilder queryBuilder = QueryBuilders.queryString("*"+wildCardQuery+"*").field("_all"); SearchRequestBuilder searchRequestBuilder = ClientProvider.instance().getClient().prepareSearch(INDEX_NAME); searchRequestBuilder.setTypes(TYPE_NAME); searchRequestBuilder.setSearchType(SearchType.DEFAULT); searchRequestBuilder.setQuery(queryBuilder); searchRequestBuilder.setFrom(0).setSize(60).setExplain(true); SearchResponse response = searchRequestBuilder.execute().actionGet(); if (response != null) { for (SearchHit hit : response.getHits()) { try { tags = hit.getSource().get("tags").toString().split(","); temporary = new Article(Long.parseLong(hit.getSource().get("id").toString()), hit.getSource().get("title").toString(), hit.getSource().get("content").toString(), new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault()).parse(hit.getSource().get("postDate").toString()), hit.getSource().get("author").toString(), tags); } catch (ParseException e) { e.printStackTrace(); } articleList.add(temporary); } } collectionSort(); } catch (IndexMissingException ex){ System.out.println("IndexMissingException: " + ex.toString()); } }queryString, which uses query parser in order to parse content, allows you to specify the field where queryString will be operated, and it also allows you to use wildcard. For QueryString, the field is index.query.default_field and "_all" is set by default, and the query string as such is operated in all fields. "*" wildcard refers to any character string, including empty ones. 9. Demo application

Web application
Elasticsearch
Database
Java (programming language)
Published at DZone with permission of Hüseyin Akdoğan. See the original article here.
Opinions expressed by DZone contributors are their own.
Trending
-
Java Concurrency: Condition
-
5 Common Data Structures and Algorithms Used in Machine Learning
-
How AI Will Change Agile Project Management
-
Grow Your Skills With Low-Code Automation Tools
Comments