solr:突出显示:hl.simple.pre/post 有时不会出现

Posted

技术标签:

【中文标题】solr:突出显示:hl.simple.pre/post 有时不会出现【英文标题】:solr : highlighting : hl.simple.pre/post doesn't appear sometime 【发布时间】:2014-07-08 10:30:03 【问题描述】:

使用 solr,我尝试使用带有 hl.simple.pre/post 的 hl.formatter 选项突出显示一些文本。

我的问题是 hl.simple.pre/post 代码有时不会出现在突出显示结果中,我不明白为什么。

例如,我称这个 URL 为:

http://localhost:8080/solr/Employees/select?q=lastName:anthan&fl=lastName&wt=json&indent=true&hl=true&hl.fl=lastName&hl.simple.pre=<em>&hl.simple.post=</em>

我明白了:

 ..."highlighting": 
    "NB0094418": 
      "lastName": [
        "Yogan<em>anthan</em>" => OK
      ]
    ,
    "NB0104046": 
      "lastName": [
        "Vijayakanthan" => KO, I want Vijayak<em>anthan</em>
      ]
    ,
    "NB0144981": 
      "lastName": [
        "Parmananthan" => KO, I want Parman<em>anthan</em>
      ]
    ,...

有人知道我为什么会有这种行为吗?

我的配置:

schema.xml

<fieldType name="nameType" class="solr.TextField">
    <analyzer type="index">
        <tokenizer class="solr.NGramTokenizerFactory" minGramSize="2" maxGramSize="50" />
        <filter class="solr.LowerCaseFilterFactory" />
        <filter class="solr.ASCIIFoldingFilterFactory" />
        <filter class="solr.TrimFilterFactory" />
        <filter class="solr.PatternReplaceFilterFactory" pattern="([^a-z])" replacement="" replace="all" />
    </analyzer>

    <analyzer type="query">
        <tokenizer class="solr.KeywordTokenizerFactory" />
        <filter class="solr.LowerCaseFilterFactory" />
        <filter class="solr.ASCIIFoldingFilterFactory" />
        <filter class="solr.TrimFilterFactory" />
        <filter class="solr.PatternReplaceFilterFactory" pattern="([^a-z])" replacement="" replace="all" />
    </analyzer>
</fieldType>

...
<fields>
    <field name="lastName" type="nameType" indexed="true" stored="true" required="true" />
</fields>

solrconfig.xml

<requestHandler name="standard" class="solr.SearchHandler" default="true">
    <lst name="defaults">
        <str name="echoParams">explicit</str>
    </lst>
</requestHandler>

...

<searchComponent class="solr.HighlightComponent" name="highlight">
    <highlighting>
        <fragmenter name="gap" default="true" class="solr.highlight.GapFragmenter">
            <lst name="defaults">
                <int name="hl.fragsize">100</int>
            </lst>
        </fragmenter>

        <fragmenter name="regex" class="solr.highlight.RegexFragmenter">
            <lst name="defaults">
                <int name="hl.fragsize">70</int>
                <float name="hl.regex.slop">0.5</float>
                <str name="hl.regex.pattern">[-\w ,/\n\&quot;&apos;]20,200</str>
            </lst>
        </fragmenter>

        <formatter name="html" default="true" class="solr.highlight.HtmlFormatter">
            <lst name="defaults">
                <str name="hl.simple.pre"><![CDATA[<em>]]></str>
                <str name="hl.simple.post"><![CDATA[</em>]]></str>
            </lst>
        </formatter>

        <encoder name="html" default="true" class="solr.highlight.HtmlEncoder" />

        <fragListBuilder name="simple" default="true" class="solr.highlight.SimpleFragListBuilder" />
        <fragListBuilder name="single" class="solr.highlight.SingleFragListBuilder" />
        <fragmentsBuilder name="default" default="true" class="solr.highlight.ScoreOrderFragmentsBuilder">
        </fragmentsBuilder>

        <fragmentsBuilder name="colored" class="solr.highlight.ScoreOrderFragmentsBuilder">
            <lst name="defaults">
                <str name="hl.tag.pre"><![CDATA[
                <b style="background:yellow">,<b style="background:lawgreen">,
                <b style="background:aquamarine">,<b style="background:magenta">,
                <b style="background:palegreen">,<b style="background:coral">,
                <b style="background:wheat">,<b style="background:khaki">,
                <b style="background:lime">,<b style="background:deepskyblue">]]></str>
                <str name="hl.tag.post"><![CDATA[</b>]]></str>
            </lst>
        </fragmentsBuilder>
    </highlighting>
</searchComponent>

【问题讨论】:

在您发布的示例中,它似乎正在返回您想要的行为。 很遗憾没有,看到第二个和第三个结果 标签丢失。 由于项目的最后期限,我正在使用 javascript 在丢失时放置 标记......但我总是对可能的解决方案或解释很感兴趣。 我现在遇到了同样的问题。有时它有效,有时则无效。我还不知道是否有模式。 我发现了我所看到的模式,并且有一个适合我的情况的解决方案。请参阅下面的答案。 【参考方案1】:

如果您问为什么您的配置定义 hl.tag.prehl.tag.post 没有出现在您提供的示例查询中,而是显示 &lt;em&gt;&lt;/em&gt; 前/后标签...

这是因为您在查询字符串中指定了hl.tag.prehl.tag.post 参数(在请求时)。因此,它们将覆盖您在 solrconfig.xml 文件中为突出显示 searchComponent 定义的defaults 设置。

要么删除那些查询字符串参数,要么将 searchComponent 配置文件设置为在 &lt;lst name="invariant"&gt; 中设置 hl.tag.prehl.tag.post 以强制这些参数覆盖任何请求时间参数。

这里是各种Configuration Settings的概述

【讨论】:

感谢您的回答,但我的问题是 &lt;em&gt;&lt;/em&gt; 前/后标签并非“总是”出现在突出显示结果中,我不明白为什么(相同如果我删除那些查询字符串参数,结果)。【参考方案2】:

直到昨天我还在处理一个非常相似的问题。我反复尝试了许多不同的解决方案,所以我最终得到的一些细节可能没有必要。但我会描述我最终的工作。简短的回答,我认为荧光笔无法在较长的字段中找到所需的术语位置信息。

首先,我看到的症状:有时会出现搜索词突出显示,有时整个字段会显示在突出显示部分,但没有突出显示信息。该模式最终基于字段的长度和搜索词的长度。我发现字段越长(实际上是被 ngrammed 的标记),可以成功突出显示的搜索词越短。不过,这不是一对一的。我发现对于包含 11 个或更少字符的字段,突出显示在所有情况下都可以正常工作。如果该字段有 12 个字符,则不会突出显示长度超过 9 个字符的 ngram。对于 15 个字符的字段,长度超过 7 个字符的 ngram 将不会突出显示。对于超过 18 个字符的字段,不会突出显示超过 6 个字符的 ngram。对于超过 21 个字符的字段,超过 5 个字符的 ngram 不会突出显示,超过 24 个字符的字段不会突出显示超过 4 个字符。 (从您上面的示例看来,您看到的具体尺寸并不完全相同,但我确实注意到文档中突出显示不起作用的名称比它起作用的名称长。 )

所以,这就是最终的工作:

    我从使用WhitespaceTokenizerNGramFilterFactory 改为使用NGramTokenizerFactory。 (您已经在使用它了,稍后我会针对这给我带来的困难提供更多信息。)但这并不足以解决问题,因为仍然没有存储术语位置。 我开始使用FastVectorHighlighter。这迫使我的架构字段的索引方式发生了一些变化(包括存储存储术语向量、位置和偏移量),并且我还必须将我的前后指标标记配置从 hl.simple.pre 更改为 hl.tag.pre(类似地*post)。

一旦我进行了这些更改,突出显示就开始持续工作。不过,这有一个副作用,就是消除了我从WhitespaceTokenizer 得到的行为。如果我有一个包含短语“这是一个测试”的字段,我最终会得到包含“s is a”、“a tes”等的 ngram,我真的只想要单个单词的 ngram,而不是的整个短语。 NGramTokenizer JavaDocs 中有一条注释,您可以覆盖 NGramTokenizer.isTokenChar() 以提供预标记,但我在网上找不到这样的示例。我将在下面添加一个。

最终结果:

WhitespaceSplittingNGramTokenizer.java:

package info.jwismar.solr.plugin;

import java.io.Reader;

import org.apache.lucene.analysis.ngram.NGramTokenizer;
import org.apache.lucene.util.Version;

public class WhitespaceSplittingNGramTokenizer extends NGramTokenizer 

    public WhitespaceSplittingNGramTokenizer(Version version, Reader input, int minGram, int maxGram) 
        super(version, input, minGram, maxGram);
    

    public WhitespaceSplittingNGramTokenizer(Version version, AttributeFactory factory, Reader input, int minGram,
            int maxGram) 
        super(version, factory, input, minGram, maxGram);
    

    public WhitespaceSplittingNGramTokenizer(Version version, Reader input) 
        super(version, input);
    

    @Override
    protected boolean isTokenChar(int chr) 
        return !Character.isWhitespace(chr);
    

WhitespaceSplittingNGramTokenizerFactory.java:

package info.jwismar.solr.plugin;

import java.io.Reader;
import java.util.Map;

import org.apache.lucene.analysis.Tokenizer;
import org.apache.lucene.analysis.ngram.NGramTokenizer;
import org.apache.lucene.analysis.util.TokenizerFactory;
import org.apache.lucene.util.AttributeSource.AttributeFactory;

public class WhitespaceSplittingNGramTokenizerFactory extends TokenizerFactory 

    private final int maxGramSize;
    private final int minGramSize;

    /** Creates a new WhitespaceSplittingNGramTokenizer */
    public WhitespaceSplittingNGramTokenizerFactory(Map<String, String> args) 
        super(args);
        minGramSize = getInt(args, "minGramSize", NGramTokenizer.DEFAULT_MIN_NGRAM_SIZE);
        maxGramSize = getInt(args, "maxGramSize", NGramTokenizer.DEFAULT_MAX_NGRAM_SIZE);
        if (!args.isEmpty()) 
            throw new IllegalArgumentException("Unknown parameters: " + args);
        
    

    @Override
    public Tokenizer create(AttributeFactory factory, Reader reader) 
        return new WhitespaceSplittingNGramTokenizer(luceneMatchVersion, factory, reader, minGramSize, maxGramSize);
    

这些需要打包成 .jar 并安装在 SOLR 可以找到的地方。一种选择是在 solrconfig.xml 中添加一个 lib 指令来告诉 SOLR 在哪里查找。 (我打电话给我的solr-ngram-plugin.jar 并将其安装在/opt/solr-ngram-plugin/。)

solrconfig.xml 内部:

<lib path="/opt/solr-ngram-plugin/solr-ngram-plugin.jar" />

schema.xml(字段类型定义):

<fieldType name="any_token_ngram" class="solr.TextField">
    <analyzer type="index">
        <tokenizer class="info.jwismar.solr.plugin.WhitespaceSplittingNGramTokenizerFactory" maxGramSize="30" minGramSize="2"/>
        <filter class="solr.LowerCaseFilterFactory" />
    </analyzer>
    <analyzer type="query">
        <tokenizer class="solr.StandardTokenizerFactory" />
        <filter class="solr.LowerCaseFilterFactory" />
        <filter class="solr.PatternReplaceFilterFactory"
            pattern="^(.30)(.*)?" replacement="$1" replace="all" />
    </analyzer>
</fieldType>

schema.xml(字段定义):

<fields>
    <field name="property_address_full" type="string" indexed="false" stored="true" />
    <field name="property_address_full_any_ngram" type="any_token_ngram" indexed="true"
        stored="true" omitNorms="true" termVectors="true" termPositions="true"
        termOffsets="true"/>
</fields>
<copyField source="property_address_full" dest="property_address_full_any_ngram" />

solrconfig.xml(请求处理程序(您可以在正常的选择 URL 中传递这些参数,如果您愿意的话)):

<!-- request handler to return typeahead suggestions -->
<requestHandler name="/suggest" class="solr.SearchHandler">
    <lst name="defaults">
        <str name="echoParams">explicit</str>
        <str name="defType">edismax</str>
        <str name="rows">10</str>
        <str name="mm">2</str>
        <str name="fl">*,score</str>
        <str name="qf">
            property_address_full^100.0
            property_address_full_any_ngram^10.0
        </str>
        <str name="sort">score desc</str>
        <str name="hl">true</str>
        <str name="hl.fl">property_address_full_any_ngram</str>
        <str name="hl.tag.pre">|-&gt;</str>
        <str name="hl.tag.post">&lt;-|</str>
        <str name="hl.fragsize">1000</str>
        <str name="hl.mergeContinuous">true</str>
        <str name="hl.useFastVectorHighlighter">true</str>
    </lst>
</requestHandler>

【讨论】:

感谢您的分析。我将尝试将此解决方案应用于我的项目。

以上是关于solr:突出显示:hl.simple.pre/post 有时不会出现的主要内容,如果未能解决你的问题,请参考以下文章

无法获得突出显示的 Solr 响应

ShingleFilterFactory 影响 Solr 中突出显示部分的大小

使用 copyField 突出显示 Solr

Solr 突出显示停用词

solr:突出显示:hl.simple.pre/post 有时不会出现

在 solr 3.4 中放置突出显示片段配置的位置