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



使用solr,我尝试使用hl突出显示一些文本。使用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>
      ]
    },...

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

My configuration:

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

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

首先,我看到的症状是:有时搜索词会突出显示,有时整个字段会显示在突出显示部分,但没有突出显示信息。该模式最终基于字段的长度和搜索词的长度。我发现,字段越长(实际上是编码的令牌),能够成功突出显示的搜索词就越短。但它不是1对1的。我发现,对于11个或更少字符的字段,高亮显示在所有情况下都很有效。如果字段有12个字符,则不会突出显示超过9个字符的ngram。对于有15个字符的字段,大于7个字符的图形不会突出显示。对于长度超过18个字符的字段,长度超过6个字符的图形不会突出显示。对于长度超过21个字符的字段,长度超过5个字符的字段不会突出显示,长度超过24个字符的字段不会突出显示超过4个字符。(看起来,从上面的例子来看,你看到的具体大小并不完全相同,但我确实注意到,在文档中,高亮显示不起作用的名字比它起作用的名字长。)

所以,这是最后的工作:

  1. 我从使用WhitespaceTokenizerNGramFilterFactory切换到使用NGramTokenizerFactory代替。(您已经在使用它了,稍后我会遇到更多的困难。)但这还不足以解决问题,因为术语位置仍然没有被存储。
  2. 我开始使用FastVectorHighlighter。这迫使我对模式字段的索引方式进行了一些更改(包括存储术语向量,位置和偏移量),并且我还必须将我的前置和后指示符标记配置从hl.simple.pre更改为hl.tag.pre(类似于*post)。

一旦我做了这些更改,高亮显示开始一致地工作。这有副作用,虽然,消除了我从WhitespaceTokenizer得到的行为。如果我有一个包含短语"this is a test"的字段,我最终得到的是包含"s is a"、"a tes"等的ngram,而且我真的只想要单个单词的ngram,而不是整个短语的ngram。在NGramTokenizer JavaDocs中有一个注释,您可以覆盖NGramTokenizer.isTokenChar()以提供预标记化,但我在web上找不到这样的示例。我将在下面包括一个。

最终结果:

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/中。)

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>

如果您正在询问为什么您的配置定义的hl.tag.prehl.tag.post没有出现在您给出的示例查询中,而是显示<em></em> pre/post标签…

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

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

下面是各种配置设置的概述

最新更新