【问题标题】:Search part of phone number with Sunspot Solr使用 Sunspot Solr 搜索部分电话号码
【发布时间】:2015-01-25 12:02:50
【问题描述】:

我正在使用 sunspot Solr 搜索引擎开发 rails 应用程序,我需要在 Solr 4.1 中索引电话号码。

例如,如果我有电话号码“+12 (456) 789-0101”,我的页面应该由查询创建:

  • +12 (456) 789-0101(电话格式正确)
  • +12 (456) 789.........(电话左侧部分格式正确)
  • .......(456) 789-0101(电话右侧部分格式正确)
  • .......(456) 789............(电话中间部分格式正确)

  • 124567890101(仅带数字的完整手机)

  • 1245678........(电话左半部分有串联号码)
  • ............890101(电话右半部分,带连接号码)
  • ......567890......(电话的中间部分,带有连接号码)

我知道我可以使用:

  • EdgeNGramFilterFactory 用于将手机拆分为 NGram(正面和背面)
  • WordDelimiterFilterFactory 用于连接号码和拆分电话的零件。

那么,我做了什么:

  1. shema.xml 中创建新的 Solr 字段类型:

    <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>

    &lt;dynamicField name="*_phone" stored="false" type="phone_number" multiValued="true" indexed="true"/&gt;

  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

    但重新索引完成后它不起作用,我只能通过查询找到结果:“完整手机”和“手机左侧”。用“middle part of phone”和“right part of phone”搜索没有任何结果。

我做错了吗?如何正确使手机部分灼热? 请帮忙。谢谢!

【问题讨论】:

    标签: solr sunspot solr4 sunspot-rails sunspot-solr


    【解决方案1】:

    (仅评论 Solr 部分,不确定 SunSpot 如何映射它)

    这里有几件事不太对:

    1. side=back 自 Solr 4.4 以来不再是一个选项,因此您可能只是获得了同一个过滤器的两个副本
    2. 无论如何,拥有相同过滤器的两个副本是不好的,因为第二个会查看第一个发布的所有令牌,事情会变得一团糟。

    这是一个匹配后缀的好方法,考虑到剥离所有随机的非数字内容和索引/查询的不对称性(来自我的AirPair Solr tutorial):

    <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>
    

    请注意,这对使用默认分析器在其中包含空格的查询没有帮助,因为它们将在空格命中字段分析之前被分解。如果您知道您正在搜索电话号码,您可以引用搜索字符串或切换到不同的 (probably field) 查询解析器。

    如果您确实想要匹配中间,也许您不想要任何这些并且只想要 NGram,而不是 EdgeNGram 分析。

    【讨论】:

    • 谢谢!据我了解,我只需要使用 NgramFilterFactory 和 PatternReplaceFilterFactory 来获得预期的结果。我需要从查询中删除空格和其他非数字符号吗?
    • 您能否给我提供 Ngram 工厂的示例,以便使用查询进行搜索:电话格式正确,电话只有数字和左/中/右部分(带和不带空格,“-”,“ +”)。非常感谢!
    • 我没有。但我认为你应该尝试用普通的过滤器替换边缘过滤器,看看是否能解决问题。最坏的情况是,您可以 copyField 到另一个字段并同时搜索。
    【解决方案2】:

    实际上,这是我的代码,它有效:

    Schema.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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-02-11
      • 1970-01-01
      • 1970-01-01
      • 2012-04-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多