Elasticsearch — это гибкий и мощный распределенный механизм поиска и анализа в реальном времени для облака, основанный на
Apache Lucene, который предоставляет возможности полнотекстового поиска. Он ориентирован на документы и не содержит схем.
исходных файлов и строк AsciiDoc в
HTML 5 ,
DocBook 4.5 и другие форматы. Помимо
Ruby- компонента Asciidoctor
, существует
проект интеграции Asciidoctor-java, который позволяет вызывать
функции Asciidoctor из
Java, не замечая, что
выполняется код Ruby .
В этой статье мы будем видеть , как мы можем использовать
Elasticsearch над
AsciiDoc документов , чтобы сделать их доступными для поиска их информации заголовка или их содержанием.
Давайте добавим необходимые зависимости:
<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>
файлов AsciiDoc в документы json.
Теперь мы можем запустить
экземпляр Elasticsearch, который в нашем случае будет встроенным экземпляром.
node = nodeBuilder().local(true).node();
Следующим шагом является анализ заголовка документа AsciiDoc , чтение его содержимого и преобразование его в документ json .
Примером документа json, хранящегося в Elasticsearch, может быть:
{
"title":"Asciidoctor Maven plugin 0.1.2 released!",
"authors":[
{
"author":"Jason Porter",
"email":"example@mail.com"
}
],
"version":null,
"content":"= Asciidoctor Maven plugin 0.1.2 released!.....",
"tags":[
"release",
"plugin"
]
}
И для преобразования AsciiDoc файла в формате JSON документа мы будем использовать XContentBuilder класс , который предоставляется Elasticsearch Java API для создания JSon документов программно.
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));
}
}
По сути, мы создаем
документ json , вызывая
методы startObject для запуска нового объекта,
метод полей для добавления новых полей и
startArray для запуска массива. Затем этот конструктор будет использоваться для визуализации эквивалентного объекта в
формате json . Обратите внимание, что мы используем
метод readDocumentHeader из
класса Asciidoctor, который возвращает атрибуты заголовка из
файла AsciiDoc без чтения и рендеринга всего документа. И, наконец, поле содержимого устанавливается со всем содержимым документа.
И теперь мы готовы начать индексацию документов. Обратите внимание , что
populateData метод получает в качестве параметра
клиентского объекта. Этот объект из
Elasticsearch
Java API и представляет собой соединение с
базой данных Elasticsearch .
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());
}
Важно отметить, что первая часть алгоритма конвертирует все наши файлы AsciiDoc (в нашем случае два) в экземпляры XContentBuilder с использованием предыдущего класса конвертера и метода convert проекта Lambdaj .
Если вы хотите, вы можете взглянуть на оба документа, использованных в этом примере, по адресу https://github.com/asciidoctor/asciidoctor.github.com/blob/develop/news/asciidoctor-java-integration-0-1-3- release.adoc и https://github.com/asciidoctor/asciidoctor.github.com/blob/develop/news/asciidoctor-maven-plugin-0-1-2-released.adoc .
Следующая часть — вставка документов в один указатель. Это делается с помощью prepareIndexметод, который требует имя индекса ( docs ), тип индекса ( asciidoctor ) и идентификатор вставляемого документа. Затем мы вызываем метод setSource, который преобразует объект XContentBuilder в json , и, наконец, вызывая execute (). ActionGet () , данные отправляются в базу данных.
Последний шаг необходим только потому, что мы используем встроенный экземпляр Elasticsearch (в производстве эта часть не требуется), который обновляет индексы, вызывая метод refresh .
После этого мы можем начать запрашивать Elasticsearch для получения информации из нашего Документы AsciiDoc .
Давайте начнем с очень простого примера, который возвращает все вставленные документы:
SearchResponse response = client.prepareSearch().execute().actionGet();
Далее мы будем искать все документы, которые были написаны Алексом Сото, который в нашем случае является одним.
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
//....
QueryBuilder matchQuery = matchQuery("author", "Alex Soto");
QueryBuilder matchQuery = matchQuery("author", "Alexander Soto");
Обратите внимание, что я ищу автора поля
строку
Alex Soto , которая возвращает только один. Другой документ написан
Джейсоном . Но интересно сказать, что если вы ищете
Александра Сото , тот же документ будет возвращен;
Elasticsearch достаточно умен, чтобы знать, что
Алекс и
Александр очень похожи, поэтому он также возвращает документ.
Еще вопросы, как насчет поиска документов, написанных кем-то, кого зовут Алекс , но не Сото .
import static org.elasticsearch.index.query.QueryBuilders.fieldQuery;
//....
QueryBuilder matchQuery = fieldQuery("author", "+Alex -Soto");
И, конечно, в этом случае результаты не возвращаются. Обратите внимание, что в этом случае мы используем
запрос поля вместо
термина запроса, и мы используем символы + и — для исключения и включения слов.
Также вы можете найти все документы, которые содержат слово, выпущенное в заголовке .
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
//....
QueryBuilder matchQuery = matchQuery("title", "released");
И, наконец, давайте найдем все документы, в которых говорится о выпуске 0.1.2, в данном случае об этом говорит только один документ, а в другом — 0.1.3.
QueryBuilder matchQuery = matchQuery("content", "0.1.2");
Теперь нам осталось только отправить запрос в базу данных Elasticsearch , что делается с помощью метода prepareSearch .
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"));
}
Обратите внимание, что в этом случае мы
печатаем содержимое AsciiDoc через консоль, но вы можете использовать
метод asciidoctor.render (String content, Options options) для отображения содержимого в требуемом формате.
Таким образом , в этой статье мы увидели , как индексировать документы с использованием
Elasticsearch , как получить важную информацию из
AsciiDoc файлов с помощью
Asciidoctor-Java-проекта интеграции , и , наконец , как выполнить несколько запросов к прикрепленным документам. Конечно, в Elasticsearch есть и другие запросы
, но цель этого поста не в том, чтобы изучить все возможности
Elasticsearch .
Также, как следствие, отметьте, насколько важно использовать
формат AsciiDoc для написания ваших документов. Без особых усилий вы можете создать поисковую систему для вашей документации. С другой стороны, представьте весь код, который потребуется для его реализации, используя любой проприетарный двоичный формат, такой как Microsoft Word
. Таким образом, мы показали другую причину использовать
AsciiDoc вместо других форматов.
