В предыдущем сообщении в блоге я объяснил различия различных типов индексов, доступных в 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