FullText в SOLR на основе подстроки конкретного поля - PullRequest
0 голосов
/ 22 сентября 2018

Я использую Apache Solr в проекте, над которым я работаю.У меня есть все настройки, и я также могу выполнять запросы SOLR.Однако - я озадачен одним поведением SOLR - и даже после поиска на форумах - не могу понять поведение.

В моей схеме solr есть один field, тип которого solr.TextField.Я пытаюсь сделать полный текстовый поиск по нему.Запрос возвращает результаты только в том случае, если я включаю подстановочный знак * как до, так и после ключевого слова поиска.Он не работает, если я включаю его только в конце (например: searchWord*)

Однако многие онлайн-форумы отмечают, что * не поддерживается в начале поиска по запросу solr / lucene.

Пожалуйста, найдите ниже schema.xml.Примечание: я использую solr v 7.4.0

<?xml version="1.0" encoding="utf-8" ?>

<schema name="blog_schema" version="1.4">

  <types>
    <fieldType name="string" class="solr.StrField" />
    <fieldType name="text" class="solr.TextField" />
    <fieldType name="long" class="org.apache.solr.schema.LongPointField" docValues="true" />
    <fieldType name="date" class="org.apache.solr.schema.DatePointField"  docValues="true" sortMissingLast="true" omitNorms="true"/>
  </types>

  <fields>
    <field name="post_id" type="string" indexed="true" stored="true" required="true" />
    <field name="title" type="string" indexed="true" stored="true" required="true" />
    <field name="author" type="string" indexed="true" stored="true" required="true" />
    <field name="corpus" type="text" indexed="true" stored="true" required="false"  />
    <field name="fullText" type="text" indexed="true" multiValued="true" />
    <copyField source="*"  dest="fullText" />
  </fields>

  <uniqueKey>post_id</uniqueKey>


</schema>

Вы можете видеть, что я определил поля corpus и fullText как имеющие тип solr.TextField.В обоих этих полях содержится много текстовых данных.

Я собираюсь выполнить полнотекстовый поиск по полям corpus или fullText.Для этой цели я использую запрос SOLR следующим образом: corpus:*Thermodynamics*

Приведенный выше запрос использует подстановочные знаки, и он работает и возвращает ожидаемые результаты.Но я не понимаю, правильно ли это делать.Многие форумы отмечают, что * в начале поискового запроса не поддерживается.Другое наблюдение: если я просто использую самое первое слово в корпусе и ищу его по corpus: Thermodynamics* - оно работает.Это, однако, не работает для слова, которое появляется позже в корпусе (то есть все слова, которые не являются первым словом в корпусе)

У меня сложилось впечатление, что SOLR поймет, что пробел / символ новой строки следует игнорировать,Итак, допустим, у корпуса есть текст: Physics has a specialization for Thermodynamics and Heat.Тогда запрос SOLR corpus: Thermodynamics* или corpus: Thermodynamics должен работать, потому что уже Thermodynamics само по себе является словом, и SOLR поймет, что игнорировать пропуски следует.Вместо этого я должен включить подстановочный знак * как в начале, так и в конце поискового запроса.

Пожалуйста, помогите мне объяснить
1. Почему это так, несмотря на то, что форумы утверждают, что * в начале поискаТермин не поддерживается SOLR.2. Правильный ли способ, которым я делаю полный текст над полем corpus?

Спасибо, Четан

1 Ответ

0 голосов
/ 22 сентября 2018

Здесь есть несколько вещей, поэтому давайте начнем с типа поля:

<fieldType name="text" class="solr.TextField" />

.. это на самом деле не определяет полезный тип поля.Для этого вам нужно подключить токенизатор и пару фильтров.Токенайзер разбивает текст на токены, и именно токены создают совпадение.Это называется цепочкой анализа.

<fieldType name="text" class="solr.TextField">
  <analyzer>
    <tokenizer class="solr.WhitespaceTokenizerFactory" />
    <filter class="solr.LowerCaseFilterFactory"/>
  </analyzer>
</fieldType>

Токенайзер Whitespace разделит «foo bar baz» на три токена: foo, bar и baz.Любые запросы будут делать то же самое и соответствовать токену для токена.Вот почему вы получите совпадение, даже если поиск будет bar baz foo, а не той же последовательностью, что и ранее.Обычно вы также хотите присоединить по крайней мере LowercaseFilter, чтобы получить поиск без учета регистра - и любые другие фильтры в зависимости от варианта использования для вашего поля и домена.Создайте несколько полей для разных совпадений и взвесьте их отдельно, чтобы получить оценку документа, наиболее подходящую для ваших пользователей.

Без этой цепочки анализа, я полагаю, вы в действительности получите то же поведение, что и строкаfield.

Тогда подстановочные знаки - если подстановочный знак присутствует, вся цепочка анализа пропускается.Это означает, что использование подстановочных знаков при поиске в тексте, как правило, является плохой идеей.Он не будет делать то, о чем вы думаете, если только вы не пытаетесь сопоставить один токен (поскольку токенайзер будет пропущен при наличии подстановочного знака).Так что вам придется делать это с осторожностью, и вы, вероятно, будете чаще сталкиваться с «почему это произошло».

Альтернативой является использование NGramFilter, который разбивает каждый набор букв.одним словом (foo становится f, fo, foo, o, oo и o) на отдельные токены.Обычно вы хотите делать это только при индексировании, поэтому используйте отдельные цепочки анализа для своего поля (вы определяете это с помощью параметра type в конфигурации - если тип не указан, эта же цепочка будет использоваться для индексации и запросов.

Причина, по которой рекомендуется использовать подстановочные знаки префикса (*foo), заключается в том, что проверка подстановочных знаков префикса обходится дороже по сравнению с проверкой подстановочного знака подстановки (foo*). В случае с постфиксом вы можете просто выполнить итерацию поиндексируйте с foo и продолжайте, пока не дойдете до того, что не начинается с foo, в то время как для *foo вы должны эффективно просматривать все термины в индексе, поскольку нет отсортированного порядка, который отслеживаетони в обратном порядке.

Введите Обратный фильтр подстановочных знаков - этот фильтр делает то, что он, в дополнение к обычным токенам, также индексирует обратный токен (или только обратный токен).Затем фильтр вызывается при запросе, а также обращается к токену запроса - эффективно индексируя oof,а затем вместо этого запросить oof* внутри.Таким образом вы получаете ускорение сохранения индекса, отсортированного для этого поля, и вам не нужно просматривать каждый токен.

Этот фильтр меняет токены, чтобы обеспечить более быстрые запросы с подстановочными знаками и префиксами.Токены без подстановочных знаков не меняются местами.

...