Поиск части номера телефона с помощью Sunspot Solr

Я разрабатываю приложение rails с поисковой системой sunspot Solr, и мне нужно индексировать телефонные номера в Solr 4.1.

Например, если у меня есть номер телефона «+12 (456) 789-0101», моя страница должна быть основана на запросах:

  • +12 (456) 789-0101 (телефон в правильном формате)
  • +12 (456) 789......... (левая часть телефона в правильном формате)
  • .......(456) 789-0101 (правая часть телефона в правильном формате)
  • .......(456) 789......... (средняя часть телефона в правильном формате)

  • 124567890101 (полный телефон только с номерами)

  • 1245678........... (левая часть телефона с цепочками номеров)
  • ............890101 (правая часть телефона с цепочками номеров)
  • ......567890...... (средняя часть телефона с цепочками номеров)

Я знаю, что могу использовать:

  • EdgeNGramFilterFactory для разделения телефона на NGrams (спереди и сзади)
  • WordDelimiterFilterFactory для объединения номеров и разделения телефона на запчасти.

Итак, что я сделал:

  1. Создайте новый тип поля Solr в shema.xml:

    <fieldType name="phone_number" class="solr.TextField"> <analyzer type="index"> <tokenizer class="solr.StandardTokenizerFactory"/> <filter class="solr.EdgeNGramFilterFactory" minGramSize="3" maxGramSize="20" side="front"/> <filter class="solr.EdgeNGramFilterFactory" minGramSize="3" maxGramSize="20" side="back"/> </analyzer> </fieldType>

    <dynamicField name="*_phone" stored="false" type="phone_number" multiValued="true" indexed="true"/>

  2. Определите доступные для поиска поля телефона как тип '*_phone':

    string :work_phone, :as => :work_phone, :stored => true do work_phone.gsub(/\D/, '') if work_phone end

    string :mobile_phone, :as => :mobile_phone, :stored => true do mobile_phone.gsub(/\D/, '') if mobile_phone end

  3. Запустите переиндексацию:

    bundle exec rake sunspot:rebuild

    Но это не работает, когда переиндексация завершена, я могу найти результаты только по запросам: "полный телефон" и "левая часть телефона". Поиск по "средняя часть телефона" и "правая часть телефона" не дает мне никаких результатов.

Я сделал что-то не так? Как правильно сделать обжиг деталей телефона? Пожалуйста помоги. Спасибо!


person bmalets    schedule 25.01.2015    source источник


Ответы (2)


(комментируя только часть Solr, не знаю, как SunSpot может ее отобразить)

Здесь есть несколько не совсем правильных моментов:

  1. side=back больше не является опцией, начиная с Solr 4.4, поэтому вы, вероятно, просто получаете две копии одного и того же фильтра.
  2. Иметь две копии одного и того же фильтра в любом случае плохо, так как второй будет просматривать все токены, выданные первым, и все станет грязным.

Вот хороший способ сопоставить суффиксы, принимая во внимание удаление всего случайного нецифрового материала и асимметрию индекса/запроса (из моего руководство по AirPair Solr):

<fieldType name="phone" class="solr.TextField">
  <analyzer type="index">
    <tokenizer class="solr.KeywordTokenizerFactory" />
    <filter class="solr.PatternReplaceFilterFactory" pattern="([^0-9])" replacement="" replace="all"/>
    <filter class="solr.ReverseStringFilterFactory"/>
    <filter class="solr.EdgeNGramFilterFactory" minGramSize="3" maxGramSize="30"/>
  </analyzer>
  <analyzer type="query">
    <tokenizer class="solr.KeywordTokenizerFactory" />
    <filter class="solr.PatternReplaceFilterFactory" pattern="([^0-9])" replacement="" replace="all"/>
    <filter class="solr.ReverseStringFilterFactory"/>
  </analyzer>
</fieldType>

Обратите внимание, что это не поможет с запросами, которые содержат пробелы с помощью анализатора по умолчанию, так как они будут разбиты на пробелы до выполнения анализа поля. Если вы знаете, что ищете номер телефона, вы можете либо указать строку поиска, либо переключиться на другую (вероятно поле) парсер запросов.

Если вы действительно хотите соответствовать середине, возможно, вы не хотите ничего из этого и просто хотите использовать NGram, а не анализ EdgeNGram.

person Alexandre Rafalovitch    schedule 26.01.2015
comment
Спасибо! так что, как я понял, мне нужно использовать NgramFilterFactory и PatternReplaceFilterFactory только для получения ожидаемых результатов. мне нужно удалить пробелы и другие нечисловые символы из запроса? - person bmalets; 26.01.2015
comment
Не могли бы вы дать мне пример с фабрикой Ngram для поиска, используя в качестве запроса: телефон в правильном формате, телефон только с цифрами и левой/средней/правой частями (с пробелами и без них, -, +). Спасибо любезно! - person bmalets; 26.01.2015
comment
У меня его нет. Но я думаю, вам следует попробовать заменить фильтр Edge на обычный и посмотреть, поможет ли это. В худшем случае вы можете copyField в другое поле и выполнить поиск в обоих. - person Alexandre Rafalovitch; 26.01.2015

Собственно, это мой код, который работает:

Схема.xml:

    <fieldType class="solr.TextField" name="phone_number" positionIncrementGap="100">       
    <analyzer type="index">         
      <tokenizer class="solr.WhitespaceTokenizerFactory"/>         
      <filter class="solr.LowerCaseFilterFactory"/>         
      <filter class="solr.NGramFilterFactory" minGramSize="3" maxGramSize="20"/>
    </analyzer>       
    <analyzer type="query">         
      <tokenizer class="solr.WhitespaceTokenizerFactory"/>         
      <filter class="solr.LowerCaseFilterFactory"/>         
      <filter class="solr.WordDelimiterFilterFactory" catenateNumbers="1"/>       
    </analyzer>     
    </fieldType>

 <dynamicField name="*_phone"  stored="false"  type="phone_number" multiValued="false" indexed="true"/>
 <dynamicField name="*_phones" stored="false"  type="phone_number" multiValued="false" indexed="true"/>

И рубиновый код:

  text :work_phone

  text :work_phone_parts, :as => :work_phone do
    "00#{work_phone.gsub(/\D/, '')}" if work_phone
  end

  text :mobile_phone

  text :mobile_phone_parts, :as => :mobile_phone do
    "00#{mobile_phone.gsub(/\D/, '')}" if mobile_phone
  end
person bmalets    schedule 28.01.2015