Я занимаюсь обновлением и тестированием большой установки и обнаружил одну проблему, которую не могу понять. У меня есть большая коллекция документов, в которых мой индекс создан следующим образом:
<collection xmlns="http://exist-db.org/collection-config/1.0">
<index xmlns:mods="http://www.loc.gov/mods/v3" xmlns:xlink="http://www.w3.org/1999/xlink">
<fulltext default="none" attributes="false"/>
<lucene>
<analyzer class="org.apache.lucene.analysis.standard.StandardAnalyzer">
<param name="stopwords" type="org.apache.lucene.analysis.util.CharArraySet"/>
</analyzer>
<analyzer id="ws" class="org.apache.lucene.analysis.WhitespaceAnalyzer"/>
<text qname="p"/>
<text qname="li"/>
<text qname="h1"/>
<text qname="h2"/>
<text qname="h3"/>
</lucene>
</index>
</collection>
В моей установке версии 2 это работает отлично. Запрос возвращает только элемент в списке (p, li, h1, h2, h3). Он также только возвращает те элементы с текстом в элементе (как и ожидалось). Функция поиска:
declare function ls:ls($collection as xs:string, $phrase as xs:string) as element()* {
for $hit in collection(xmldb:encode-uri($collection))//*[ft:query(.,
<query>
<phrase>{$phrase}</phrase>
</query>
)]
order by $hit/ancestor::div[@class='content']/@doc/string()
return
<tr>
<td>
{$hit/ancestor::div[@class='content']/@doc/string()}
</td>
<td>
{$hit/ancestor::div[@class='content']/@title/string()}
</td>
<td>
{local-name($hit)}
</td>
<td class="hit_text">
{normalize-space($hit)}
</td>
</tr>
};
Чтобы увидеть результат, вот снимок результатов веб-страницы:
Конечно, это не показывает все результаты, но поверьте мне ... он возвращает только названные элементы и только те, в которых есть "сердце".
После экспорта / импорта контента для установки новой версии 4 все остальное работает идеально. Однако даже после переиндексации содержимого тот же самый xQuery возвращает нежелательные элементы более высокого уровня (например, div), а также возвращает элементы, которые не содержат поисковую фразу.
Например, тот же самый запрос показывает такой результат:
Теперь, как ни странно, если я изменю функцию, чтобы удалить подстановочный знак и перейти только после «h1» (или любого другого из названных элементов), это сработает:
for $hit in collection(xmldb:encode-uri($collection))//h1[ft:query(.,
Урожайность:
Вы можете видеть, что в отличие от предыдущего примера, h1 без "сердца" не возвращается.
Что я пропустил при обновлении? Есть ли какие-то изменения в Lucene, которые я пропустил или не понимаю?
Обновлять
Как взломать (ИМХО) это работает:
let $targets := collection(xmldb:encode-uri($collection))//*[local-name(.) = 'p' or local-name(.) = 'h1' or local-name(.) = 'h2' or local-name(.) = 'h3' or local-name(.) = 'li']
for $hit in $targets[ft:query(.,
<query>
<phrase>{$phrase}</phrase>
</query>
)]
Но если я уберу создание nodeset $ target и поместил collection () в «for», это не сработает.
Обновление II
Должно быть что-то не так (полный текст не включен, не запущен или?), Потому что выполнение аналогичного запроса в обоих случаях занимает путь дольше на новом, обновленном сервере.
Так что же я упустил при обновлении? У меня есть conf.xml, вызывающий Lucene в обоих. Любые подсказки о том, что искать, были бы замечательными.
Обновление III
Может это в логах проблема? Я сомневаюсь, что поиск в журнале версии 2.x показывает ту же ошибку.
2018-12-19 19:27:05,570 [qtp14962548-143] ERROR (AnalyzerConfig.java [configureAnalyzer]:173) - Lucene index: analyzer class org.apache.lucene.analysis.WhitespaceAnalyzer not found. (org.apache.lucene.analysis.WhitespaceAnalyzer)
2018-12-19 19:27:38,852 [qtp14962548-43] INFO (NativeBroker.java [reindexCollection]:1844) - Start indexing collection /db/EIDO/data/Core
2018-12-19 19:27:54,837 [qtp14962548-43] INFO (NativeBroker.java [reindexCollection]:1854) - Finished indexing collection /db/EIDO/data/Core in 15985 ms.
Обновление IV
Я изменил collection.xconf на как было предложено для удаления стоп-слов и удаления WhitespaceAnalyzer:
<collection xmlns="http://exist-db.org/collection-config/1.0">
<index xmlns:mods="http://www.loc.gov/mods/v3" xmlns:xlink="http://www.w3.org/1999/xlink">
<fulltext default="none" attributes="false"/>
<lucene>
<analyzer class="org.apache.lucene.analysis.standard.StandardAnalyzer"/>
<text qname="p"/>
<text qname="li"/>
<text qname="h1"/>
<text qname="h2"/>
<text qname="h3"/>
</lucene>
</index>
</collection>
Переиндексировал коллекцию. Из журнала:
2018-12-20 02:14:56,803 [qtp31631875-34] INFO (NativeBroker.java [reindexCollection]:1844) - Start indexing collection /db/EIDO/data/Core
2018-12-20 02:15:16,553 [qtp31631875-34] INFO (NativeBroker.java [reindexCollection]:1854) - Finished indexing collection /db/EIDO/data/Core in 19750 ms.
Я получаю точно такой же результат.
Обновить V
Думаю, я плыву на лодке. Собираюсь снова запустить весь процесс в эти выходные, удалить все и повторить попытку, но это не имеет смысла и не работает.
Обновление VI
Я не люблю кататься на лодках! Теперь, глядя на результаты, по сути, это поиск в текущей установке:
for $hit in collection(xmldb:encode-uri($collection))//*[ft:query(.,
<query>
<phrase>{$phrase}</phrase>
</query>
)]
Возвращает каждый элемент в базе данных, независимо от того, содержат ли они фразу $ или нет. Он возвращает div, затем дочерний p, затем, возможно, дочерний диапазон. Все они. Не имеет значения, существует ли слово в тексте на самом деле.
Если я изменю подстановочный знак «*» на «h1», он вернет только те h1, в которых действительно есть этот текст. Так что-то не то или сломано или? Я, конечно, могу изменить список элементов, переданный в ft: query, на конкретные рассматриваемые элементы (p, h1, h2, h3, li), но этот запрос занимает вечность за 4,5 и несколько секунд за 2.
Вероятно последнее обновление
Я сдался и переустановил все, включая Monex. Я реэкспортировал существующую БД и импортировал ее. Я меняю только порт на 80, хотя обычно делаю и другие изменения.
Теперь даже попытка запустить панель управления (после импорта) дает:
javax.servlet.ServletException: javax.servlet.ServletException: An error occurred while processing request to /exist/apps/dashboard/: err:XPST0081 error found while loading module restxq: Error while loading module modules/restxq.xql: Invalid qname text:groups
at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:146)
at org.eclipse.jetty.server.handler.gzip.GzipHandler.handle(GzipHandler.java:724)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
at org.eclipse.jetty.server.Server.handle(Server.java:531)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:352)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:260)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:281)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:102)
at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:118)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:760)
at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:678)
Это указывает мне на то, что экспорт базы данных, а затем повторный импорт никогда не будет работать, если у вас установлены другие приложения.
К сожалению, мне приходится искать альтернативные решения. Я мог бы попытаться просто восстановить данные или что-то в этом роде, но у приложения было 10 000 пользователей. Это невозможно воссоздать.
В настоящее время я могу только сказать, что он не готов к работе в прайм-тайм и будет просто находиться в старой базе данных, которая отлично работает и работает уже много лет.
И просто обратите внимание ... после установки свежей, чистой базы данных и без изменений я могу получить доступ к Monex или панели инструментов. Если я импортирую из своей резервной копии (как требуется, потому что она не совместима с двоичными файлами), все ломается.
Для меня это очевидная проблема для разработчиков.
Обновить снова
Я сделал полностью чистую установку. После этого я могу получить доступ к Monex без проблем. Затем я восстанавливаю свою базу данных. ПРИМЕЧАНИЕ. На данный момент есть вопрос, который спрашивает, хочу ли я обновить приложения. Не уверен, что ответ правильный, может быть, это одна из проблем, и я отвечаю неправильно (я отвечаю нет).
После того, как все будет переустановлено, я могу нормально добраться до БД и всего моего приложения. Но когда я пытаюсь запустить Monex, я получаю:
<exception>
<path>/db/apps/monex/modules/view.xql</path>
<message>err:XPST0081 error found while loading module indexes: Error while loading module indexes.xqm: Invalid qname text:index-terms</message>
</exception>
Правильный ли ответ - да, чтобы обновить приложения? Я предполагаю, что это означает, что Monex, который я установил с помощью чистой установки, перезаписан моей резервной копией версии 2, и это вызывает ошибку.
Я взломал часть индекса monex, вызывающую проблему, и запустил Monex. Итак, он использует Lucene:
Итак, одно наблюдение заключается в том, почему Monex работает нормально, но восстановление моей (старой) БД убивает его. Это не должно быть AFAIK.
может быть, кто-то может объяснить мне этот результат, я не понимаю второй пункт, но подозреваю, что это тот, который возвращает все:
ОК, работает
Так. Во-первых, я понял, что восстановление моего / db разрушит все / apps (например, monex) при новой установке. Мне кажется странным или плохое планирование для меня или других. Итак, чтобы решить эту проблему, у меня есть свежая резервная копия установки.
После установки новой версии eXist я восстанавливаю свою старую базу данных, а затем сразу же снова восстанавливаю новую версию. Это перезаписывает все / apps (например, monex) последними версиями, которые были установлены из моей резервной копии, но не разрушает мою. Простите, смешно.
Теперь после этого я мог протестировать и увидеть, что используется индекс Lucene. Но это все, что он мне сказал, не более (как я подозревал).
Очевидно, что при интеграции Lucene поведение изменилось. В моей старой версии я отправлял каждый элемент, и он возвращал только хиты. В этой новой версии вы не можете этого сделать. Если вы отправите что-то вроде того, что сделано в приведенном выше коде, он все равно вернет это как «хит», даже если его нет. Следовательно, $ collection // * отправляет всю структуру в запрос и возвращает все, независимо от того, есть ли совпадение или нет. Раньше он так себя не вел.
Итак, решение (а это такая хитрость, которую я ненавижу даже говорить), что вы можете отправлять элементы только по запросу, который вы хотите найти, чтобы увидеть, есть ли контент, который является хитом. УХ ТЫ. Опять же, извините, но если я ошибаюсь, пожалуйста, покажите мне, что это полный взлом. Если я создам индекс всех p, я ожидаю, что p вернется, только если я сделаю общий поиск, отправив его p, h1 и т. Д. Что происходит сейчас, он отправляет все обратно, ударил или нет, если вы не попросите точно то же самое имя элемента, который вы проиндексировали.
Это похоже на позднюю / раннюю привязку. В старом eXist я отправлял $ coll / [ft: query ..., и он возвращал то, что у меня было как идентифицированные элементы в моем индексе. Теперь это не работает, поэтому вы не можете выполнить цикл for в $ coll / [ft: query ..., поскольку он по-прежнему возвращает все. ИМХО, что это неправильно.
Чтобы решить эту проблему, я сначала выполнил поиск, а затем перебирал результаты.
declare function ls:ls($collection as xs:string, $phrase as xs:string) as element()* {
let $coll := collection(xmldb:encode-uri($collection))
let $hits := ($coll//p | $coll//li | $coll//h1 | $coll//h2 | $coll//h3)[ft:query(.,
<query>
<phrase>{$phrase}</phrase>
</query>
)]
for $hit in $hits
order by $hit/ancestor::div[@class='content']/@doc/string()
return
<tr>
<td>
{$hit/ancestor::div[@class='content']/@doc/string()}
</td>
<td>
{$hit/ancestor::div[@class='content']/@title/string()}
</td>
<td>
{local-name($hit)}
</td>
<td class="hit_text">
{normalize-space($hit)}
</td>
</tr>
}
;
И теперь я обновился, чтобы проверить, и это тоже работает:
let $hits := (collection(xmldb:encode-uri($collection))//*)[ft:query(.,
<query>
<phrase>{$phrase}</phrase>
</query>
)]
for $hit in $hits ...
Так что теперь это так близко к тому, что было у меня раньше, мне НЕ нужно идти за явными элементами, что является правильным. Проблема в том, что теперь они не могут быть в цикле for.
Ключ здесь:
(collection(xmldb:encode-uri($collection))//*)
против:
collection(xmldb:encode-uri($collection))//*
Итак ... все это ... и решение - цикл for должен быть:
for $hit in (collection(xmldb:encode-uri($collection))//*)[ft:query(.,
<query>
<phrase>{$phrase}</phrase>
</query>
)]
Поскольку теперь эта проблема решена, возможно, кто-то захочет объяснить, почему старый код, который не использовал () для отдельных элементов, работал, но не работает в последней версии eXist.
Если быть точным, обе системы у меня открыты для тестирования.
Версия 2x:
for $hit in collection(xmldb:encode-uri($collection))//*[ft:query(.,
Одна секунда, правильный ответ.
for $hit in (collection(xmldb:encode-uri($collection))//*)[ft:query(.,
17 секунд, правильный ответ.
Версия 4.5:
for $hit in collection(xmldb:encode-uri($collection))//*[ft:query(.,
10 секунд, совершенно неправильный ответ (возвращены div и non-hit)
for $hit in (collection(xmldb:encode-uri($collection))//*)[ft:query(.,
одна секунда, правильный ответ.
Мне кажется, что в старом eXist запрос ничего не возвращал, а в этом новом eXist, кажется, возвращает результат для каждого отправленного элемента, и если индекса не существует, он все равно возвращает его.
Последнее обновление
Просматривая чистую установку conf.xml
, я нашел комментарий в записи xquery для enable-query-rewriting
. Этот комментарий предполагает, что это экспериментальный вариант, и установка «да» может привести к неверным результатам.
Я хотел бы отметить, что я не верю, что коснулся этого, и при установке по умолчанию это значение установлено на «да». Я сохранил conf.xml из чистой установки, так как я многое в нем меняю (конечно), глядя на чистую установку, я вижу следующее:
<xquery enable-java-binding="no" disable-deprecated-functions="no"
enable-query-rewriting="yes" backwardCompatible="no"
enforce-index-use="always"
raise-error-on-failed-retrieval="no">
Я изменил значение на «нет» и перезапустил exist-db. Теперь все работает, как и раньше, теперь у меня нет проблем с поиском, и он возвращает именно то, что я ожидал, с запросом, написанным точно так же, как в версии 2x.
Итак ... то, что, как мне кажется, я узнал
Я реализовал новые индексы диапазонов и переиндексировал коллекцию на основе комментариев ниже и снова включил перезапись запроса. Проверяя monex, я вижу индексы, но в моих запросах они не использовались, индекс был указан как устаревший «диапазон», а оптимизация - как «Нет индекса».
Я обнаружил, что не могу этого сделать (что, как я полагаю, будет делать подстановочный знак):
($ collection // foo | $ collection // bar) [содержит (., $ фраза)]
или это
($ collection // foo, $ collection // bar) [содержит (., $ фраза)]
или это
$ testnodes: = $ collection // foo | $ collection // бар
тогда
$ testnodes [содержит (., $ фраза)]
Хотя он работает, он не использует индекс нового диапазона. Они всегда сообщают об отсутствии используемого индекса.
Но здесь используются полностью оптимизированные индексы нового диапазона:
$ collection // foo [содержит (., $ фраза)] | $ collection // bar [содержит (., $ фраза)]