В предыдущем сообщении в блоге я объяснил различия различных типов индексов, доступных в Neo4j. Общим требованием для многих проектов является использование полнотекстовых индексов. В текущих версиях Neo4j (2.1.5 на данный момент) это может быть достигнуто только с использованием ручных индексов.
В этой статье я хочу объяснить, как вы можете использовать специфичные для языка анализаторы для полнотекстовой индексации и как выполнять их поиск по регулярному выражению.
При рассмотрении справочного руководства по полнотекстовой индексации существует идея предоставления пользовательского класса анализатора путем указания параметра конфигурации analyzerпри создании индекса. Это значение — полное имя класса анализатора. Существует два способа создания индекса вручную, либо с использованием Java API
GraphDatabaseService graphDb = ....
IndexManager indexManager = graphDb.index()
try (Transaction tx = graphDb.beginTx()) {
Map<String,String> params = Collections.singletonMap("analyzer",
"my.package.Analyzer")
Index index = indexManager.forNodes("myfulltextindex", params);
}
или используя REST API (используя замечательный клиент командной строки httpie http )
http -v -j localhost:7474/db/data/index/node \
name=myfulltextindex config:='{"analyzer":"my.package.Analyzer"}'
Lucene предоставляет дополнительный набор анализаторов языка. Эти анализаторы имеют некоторые знания о языке, на котором они работают, и используют его для определения слова, см. Http://www.evelix.ch/unternehmen/Blog/evelix/2013/11/inner-workings-of-the-german. -Analyzer-in-Lucene для получения подробной информации о внутренностях GermanAnalyzer. Например, немецкое слово для домов «Häuser» связано с его единственной формой «Haus». Следовательно, запрос «Haus» извлекает все оба случая «Haus» и «Häuser».
Специфичные для языка анализаторы находятся в необязательном jar-файле lucene-analyzers-3.6.2.jar, который не поставляется по умолчанию с Neo4j. Поэтому скопируйте lucene-analyzers-3.6.2.jarв pluginsпапку Neo4j .
Например, при попытке использовать Lucene’s GermanAnalyzer с помощью
http -v -j localhost:7474/db/data/index/node name=fulltext_de \
config:='{"analyzer":"org.apache.lucene.analysis.de.GermanAnalyzer"}'
вы получаете HTTP-статус 500. Файлы журнала показывают странное исключение java.lang.InstantiationException: org.apache.lucene.analysis.de.GermanAnalyzer. Причиной этого исключения является то, что Neo4j пытается создать экземпляр класса анализатора, используя конструктор по умолчанию noarg. К сожалению, специфичные для языка анализаторы Lucene не имеют такого конструктора, см. Javadocs . Решением для этого является написание тонкого класса анализатора с конструктором по умолчанию. Внутренне этот класс использует предоставленный Lucene анализатор в качестве делегата.
Чтобы упростить процесс настройки, я создал небольшой проект на github под названием neo4j-fti . Содержит упомянутые обертки в упаковке org.neo4j.contrib.fti.analyzersдля всех языков, имеющих анализатор люцена. Он также предоставляет расширение ядра для Neo4j для автоматического создания полнотекстовых индексов с помощью параметра конфигурации. В neo4j.propertiesвам необходимо установить:
fullTextIndexes=fulltext_de:org.neo4j.contrib.fti.analyzers.German,\
fulltext_en:org.neo4j.contrib.fti.analyzers.English
Кроме того, в этом проекте представлен пример использования регулярного выражения для поиска в индексе. Используя Java API, вам нужно передать Lucene RegexQueryна основе Termхранения вашего регулярного выражения. Этот RegexQueryкласс также не является частью lucene-core, поэтому обязательно поместите его lucene-queriesв папку Neo4j plugins. Этот пример представлен в неуправляемом расширении с использованием следующего фрагмента кода :
try (Transaction tx = graphDatabaseService.beginTx()) {
IndexManager indexManager = graphDatabaseService.index();
if (!indexManager.existsForNodes(indexName)) {
throw new IllegalArgumentException("index " + indexName + " does not exist");
}
Index index = indexManager.forNodes(indexName);
IndexHits hits = index.query(new RegexQuery(new Term(field, regex)));
List result = new ArrayList<>();
for (Node node: hits) {
result.add(node.getId());
}
}
Предполагая, что названный индекс fulltext_deбыл настроен с использованием немецкого анализатора (см. Выше), используйте следующий код, снова используя httpie, чтобы создать узел, добавьте его в полнотекстовый индекс и выполните запрос индекса регулярного выражения:
# create a node
http -j localhost:7474/db/data/cypher query="create (n:Blog {description:'Auf der Straße stehen fünf Häuser'}) return id(n)"
# put it to the index:
http -j localhost:7474/db/data/index/node/fulltext_de \
uri="http://localhost:7474/db/data/node/xxxx" \
key="description" value="Auf der Straße stehen fünf Häuser"
# query the index for words starting with "h" and ending with "s"
http localhost:7474/regex/fulltext_de/description/h.*s