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":"[email protected]" } ], "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 вместо других форматов.