DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

How does AI transform chaos engineering from an experiment into a critical capability? Learn how to effectively operationalize the chaos.

Data quality isn't just a technical issue: It impacts an organization's compliance, operational efficiency, and customer satisfaction.

Are you a front-end or full-stack developer frustrated by front-end distractions? Learn to move forward with tooling and clear boundaries.

Developer Experience: Demand to support engineering teams has risen, and there is a shift from traditional DevOps to workflow improvements.

Related

  • Doris vs Elasticsearch: A Comparison and Practical Cost Case Study
  • Designing a Blog Application Using Document Databases
  • Elasticsearch Query and Indexing Architecture
  • Dynamic Watermarking of Bitmaps in Databases

Trending

  • RAG vs. CAG: A Deep Dive into Context-Aware AI Generation Techniques
  • KubeVirt: Can VM Management With Kubernetes Work?
  • Taming Billions of Rows: How Metadata and SQL Can Replace Your ETL Pipeline
  • AI's Cognitive Cost: How Over-Reliance on AI Tools Impacts Critical Thinking
  1. DZone
  2. Data Engineering
  3. Big Data
  4. Searchable Documents? Yes You Can. Another Reason to Choose AsciiDoc

Searchable Documents? Yes You Can. Another Reason to Choose AsciiDoc

By 
Alex Soto user avatar
Alex Soto
·
Jun. 10, 13 · Interview
Likes (0)
Comment
Save
Tweet
Share
4.5K Views

Join the DZone community and get the full member experience.

Join For Free

Elasticsearch is a flexible and powerful open source, distributed real-time search and analytics engine for the cloud based on Apache Lucene which provides full text search capabilities. It is document oriented and schema free.


Asciidoctor is a pure Ruby processor for converting AsciiDoc source files and strings into HTML 5, DocBook 4.5 and other formats. Apart of Asciidoctor Ruby part, there is an Asciidoctor-java-integration project which let us call Asciidoctor functions from Java without noticing that Ruby code is being executed.


In this post we are going to see how we can use Elasticsearch over AsciiDocdocuments to make them searchable by their header information or by their content.


Let's add required dependencies:

<dependencies>
	
	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
		<version>4.11</version>
		<scope>test</scope>
	</dependency>
	<dependency>
		<groupId>com.googlecode.lambdaj</groupId>
		<artifactId>lambdaj</artifactId>
		<version>2.3.3</version>
	</dependency>
	<dependency>
		<groupId>org.elasticsearch</groupId>
		<artifactId>elasticsearch</artifactId>
		<version>0.90.1</version>
	</dependency>
	<dependency>
		<groupId>org.asciidoctor</groupId>
		<artifactId>asciidoctor-java-integration</artifactId>
		<version>0.1.3</version>
	</dependency>
		
</dependencies>
Lambdaj library is used to convert AsciiDoc files to a json documents.
Now we can start an Elasticsearch instance which in our case it is going to be an embedded instance.
node = nodeBuilder().local(true).node();

Next step is parse AsciiDoc document header, read its content and convert them into a json document.

An example of json document stored in Elasticsearch can be:

{
   "title":"Asciidoctor Maven plugin 0.1.2 released!",
   "authors":[
      {
         "author":"Jason Porter",
         "email":"[email protected]"
      }
   ],
   "version":null,
   "content":"= Asciidoctor Maven plugin 0.1.2 released!.....",
   "tags":[
      "release",
      "plugin"
   ]
}

And for converting an AsciiDoc File to a json document we are going to useXContentBuilder class which is provided by ElasticsearchJava API to create jsondocuments programmatically.

package com.lordofthejars.asciidoctor;
 
import static org.elasticsearch.common.xcontent.XContentFactory.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;
 
import org.asciidoctor.Asciidoctor;
import org.asciidoctor.Author;
import org.asciidoctor.DocumentHeader;
import org.asciidoctor.internal.IOUtils;
import org.elasticsearch.common.xcontent.XContentBuilder;
 
import ch.lambdaj.function.convert.Converter;
 
public class AsciidoctorFileJsonConverter implements Converter<File, XContentBuilder> {
	
	private Asciidoctor asciidoctor;
	
	public AsciidoctorFileJsonConverter() {
		this.asciidoctor = Asciidoctor.Factory.create();
	}
	
	public XContentBuilder convert(File asciidoctor) {
		
		DocumentHeader documentHeader = this.asciidoctor.readDocumentHeader(asciidoctor);
		
		XContentBuilder jsonContent = null;
		try {
			jsonContent = jsonBuilder()
				    .startObject()
				    .field("title", documentHeader.getDocumentTitle())
				    .startArray("authors");
				    
					Author mainAuthor = documentHeader.getAuthor();
			
					jsonContent.startObject()
								.field("author", mainAuthor.getFullName())
								.field("email", mainAuthor.getEmail())
								.endObject();
					
					List<Author> authors = documentHeader.getAuthors();
					
					for (Author author : authors) {
						jsonContent.startObject()
								.field("author", author.getFullName())
								.field("email", author.getEmail())
								.endObject();
					}
					
				    jsonContent.endArray()
				    		.field("version", documentHeader.getRevisionInfo().getNumber())
				    		.field("content", readContent(asciidoctor))
				    		.array("tags", parseTags((String)documentHeader.getAttributes().get("tags")))
				    .endObject();
		} catch (IOException e) {
			throw new IllegalArgumentException(e);
		}
		
		return jsonContent;
	}
 
	private String[] parseTags(String tags) {
		tags = tags.substring(1, tags.length()-1);
		return tags.split(", ");
	}
	
	private String readContent(File content) throws FileNotFoundException {
		return IOUtils.readFull(new FileInputStream(content));
	}
	
}
Basically we are building the json document by calling startObject methods to start a new object, field method to add new fields, and startArray to start an array. Then this builder will be used to render the equivalent object in json format. Notice that we are using readDocumentHeader method from Asciidoctor class which returns header attributes from AsciiDoc file without reading and rendering the whole document. And finally content field is set with all document content.
And now we are ready to start indexing documents. Note that populateData method receives as parameter  a Client object. This object is from Elasticsearch Java APIand represents a connection to Elasticsearch database.
import static ch.lambdaj.Lambda.convert;
//....
 
private void populateData(Client client) throws IOException {
		List<File> asciidoctorFiles = new ArrayList<File>() {{
			add(new File("target/test-classes/java_release.adoc"));
			add(new File("target/test-classes/maven_release.adoc"));
		}};
		
		List<XContentBuilder> jsonDocuments = convertAsciidoctorFilesToJson(asciidoctorFiles);
		
		for (int i=0; i < jsonDocuments.size(); i++) {
			client.prepareIndex("docs", 
                                         "asciidoctor", Integer.toString(i)).setSource(jsonDocuments.get(i)).execute().actionGet();
			
		}
                
                client.admin().indices().refresh(new RefreshRequest("docs")).actionGet();
}
 
private List<XContentBuilder> convertAsciidoctorFilesToJson(List<File> asciidoctorFiles) {
		return convert(asciidoctorFiles, new AsciidoctorFileJsonConverter());
}

It is important to note that the first part of the algorithm is converting all our AsciiDocfiles (in our case two) to XContentBuilder instances by using previous converter class and the method convert of Lambdaj project.

If you want you can take a look to both documents used in this example in https://github.com/asciidoctor/asciidoctor.github.com/blob/develop/news/asciidoctor-java-integration-0-1-3-released.adoc and https://github.com/asciidoctor/asciidoctor.github.com/blob/develop/news/asciidoctor-maven-plugin-0-1-2-released.adoc.

Next part is inserting documents inside one index. This is done by using prepareIndexmethod, which requires an index name (docs), an index type (asciidoctor), and the idof the document being inserted. Then we call setSource method which transforms theXContentBuilder object to json, and finally by calling execute().actionGet(), data is sent to database.

The final step is only required because we are using an embedded instance ofElasticsearch (in production this part should not be required), which refresh the indexes by calling refresh method.

After that point we can start querying Elasticsearch for retrieving information from our AsciiDoc documents.

Let's start with very simple example, which returns all documents inserted:

SearchResponse response = client.prepareSearch().execute().actionGet();

Next we are going to search for all documents that has been written by Alex Sotowhich in our case is one.

import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
//....
QueryBuilder matchQuery =  matchQuery("author", "Alex Soto");
 
QueryBuilder matchQuery =  matchQuery("author", "Alexander Soto");
Note that I am searching for field author the string Alex Soto, which returns only one. The other document is written by Jason. But it is interesting to say that if you search for Alexander Soto, the same document will be returned; Elasticsearch is smart enough to know that Alex and Alexander are very similar names so it returns the document too.


More queries, how about finding documents written by someone who is called Alex, but not Soto.

import static org.elasticsearch.index.query.QueryBuilders.fieldQuery;
 
//....
 
QueryBuilder matchQuery =  fieldQuery("author", "+Alex -Soto");
And of course no results are returned in this case. See that in this case we are using afield query instead of a term query, and we use +, and - symbols to exclude and include words.


Also you can find all documents which contains the word released on title.

import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
 
//....
 
QueryBuilder matchQuery =  matchQuery("title", "released");

And finally let's find all documents that talks about 0.1.2 release, in this case only one document talks about it, the other one talks about 0.1.3.

QueryBuilder matchQuery =  matchQuery("content", "0.1.2");

Now we only have to send the query to Elasticsearch database, which is done by using prepareSearch method.

SearchResponse response = client.prepareSearch("docs")
			  .setTypes("asciidoctor")
			  .setQuery(matchQuery)
			  .execute()
			  .actionGet();
		
SearchHits hits = response.getHits();
	
for (SearchHit searchHit : hits) {
      System.out.println(searchHit.getSource().get("content"));
}
Note that in this case we are printing the AsciiDoc content through console, but you could use asciidoctor.render(String content, Options options) method to render the content into required format.

So in this post we have seen how to index documents using Elasticsearch, how to get some important information from AsciiDoc files using Asciidoctor-java-integration project, and finally how to execute some queries to inserted documents. Of course there are more kind of queries in Elasticsearch, but the intend of this post wasn't to explore all possibilities of Elasticsearch.
Also as corollary, note how important it is using AsciiDoc format for writing your documents. Without much effort you can build a search engine for your documentation. On the other side, imagine all code that would be required to implement the same using any proprietary binary format like Microsoft Word. So we have shown another reason to use AsciiDoc instead of other formats.


Document Database AsciiDoc Elasticsearch

Published at DZone with permission of Alex Soto, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Doris vs Elasticsearch: A Comparison and Practical Cost Case Study
  • Designing a Blog Application Using Document Databases
  • Elasticsearch Query and Indexing Architecture
  • Dynamic Watermarking of Bitmaps in Databases

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • [email protected]

Let's be friends: