Warm tip: This article is reproduced from serverfault.com, please click

javascript-Apache Solr提取,根据查询突出显示HTML元素,过滤查询条件

(javascript - Apache Solr extract, highlight HTML elements based on query, filter query terms)

发布于 2020-12-13 01:48:57

更新。(+ 18d)编辑了标题,并提供了回答原始问题的答案。


tl / dr

我正在索引HTML页面并将<p>...</p>内容作为搜索查询返回的摘要转储但是,我不需要/不需要所有这些内容(只是查询周围的上下文与文本匹配)。

背景

在我的[经典]模式中,

<fieldType name="text_general" class="solr.TextField" positionIncrementGap="100" 
autoGeneratePhraseQueries="true" multiValued="true">

<field name="p" type="text_general" indexed="true" stored="true" multiValued="true" 
omitNorms="true" termVectors="true" />

这些在我的solrconfig.xml中

<str name="queryAnalyzerFieldType">text_general</str>

<updateProcessor class="solr.AddSchemaFieldsUpdateProcessorFactory" name="add-schema-fields">
  <lst name="typeMapping">
    <str name="valueClass">java.lang.String</str>
    <str name="fieldType">text_general</str>
    <lst name="copyField">
      <str name="dest">*_str</str>
      <int name="maxChars">256</int>
    </lst>
    ...

<initParams path="/update/**,/query,/select,/spell">
  <lst name="defaults">
    <str name="df">_text_</str>
  </lst>
</initParams>

<requestHandler name="/update/extract"
class="org.apache.solr.handler.extraction.ExtractingRequestHandler">
  <lst name="defaults">
    <str name="lowernames">true</str>
    <str name="uprefix">ignored_</str>
    <str name="capture">div</str>
    <str name="fmap.div">div</str>
    <str name="capture">p</str>
    <str name="fmap.p">p</str>
    <str name="processor">uuid,remove-blank,field-name-mutating,parse-boolean,
               parse-long,parse-double,parse-date</str>
  </lst>
</requestHandler>

<requestHandler name="/query" class="solr.SearchHandler">
  <lst name="defaults">
    <str name="echoParams">explicit</str>
    <str name="wt">json</str>
    <str name="indent">true</str>
  </lst>
</requestHandler>

<queryResponseWriter name="json" class="solr.JSONResponseWriter">
  <!-- For the purposes of the tutorial, JSON responses are written as
   plain text so that they are easy to read in *any* browser.
   If you expect a MIME type of "application/json" just remove this override.
  -->
  <str name="content-type">text/plain; charset=UTF-8</str>
</queryResponseWriter>


我得到了这个结果[Solr Admin UI; 此处显示的传真],

"p":["Sentence 1. Sentence 2. Sentence 3. Sentence 4. ..."]

在源HTML文档的句子单独出现在P标签,例如<p>Sentence 1.</p><p>Sentence 1.</p>,...

问题

  1. 如何单独索引它们?我的基本原理是,我想在搜索结果目标周围显示上下文的摘要(而不是整个带有p标签的内容)。

  2. 另外,在Linuxgrep命令中,我们可以例如在匹配的行之前和之后返回一行(-C1,context,argument)。我们可以在这里做类似的事情吗?

    即,如果Solr查询匹配项位于句子2中,则该摘要将包含句子1-3?

我尝试为p元素分配唯一的ID(<p id="a">...</p> <p id="b">...</p>但我只是在Solr中得到了它,

"p":["a Sentence 1. b Sentence 2. Sentence d 3. Sentence d 4. ..."]
Questioner
Victoria Stuart
Viewed
11
Victoria Stuart 2021-01-01 09:24:24

更新[2020-12-31]

  • 请忽略我自己的问题的答案,因为18天过去了,其中只有一条评论,没有答案。

我正在构建一个以Solr为后端的搜索页面,其灵感来自以下Ajax Solr教程。 https://github.com/evolvingweb/ajax-solr

最终,我决定放弃Solr的强调方式,而选择了更为灵活的定制JavaScript(JS)解决方案。

基本上,我:

  • 收集数组中的Solr查询(q)和过滤查询(fq)值(术语)(如下所示的简化示例;附加了更完整的JS代码)

    for (var i = 0, l = this.manager.response.response.docs.length; i < l; i++) {
        var doc = this.manager.response.response.docs[i];
    }
    
  • 通过JS正则表达式提取与这些术语(单词)匹配的句子

    var mySentences = doc_p.replace(/([.?!])\s*(?=['"A-Z])/g, "$1|").split("|");
    

    其中doc.p的Solr字段(在中定义schema.xml)对应于索引的HTML p元素(<p> ... </ p>)文本。

  • 突出显示那些查询词

    var query = this.manager.store.get('q').value;  /* or loop over array */
    
    const replacer = (str, replace) => {
        const re = new RegExp(`(${replace})`, 'gi')
        return str.replaceAll(re, '<font style="background:#FFFF99">$1</font>')
    }
    var doc_p_hl = replacer(doc.p.toString(), query);
    
  • 使用这些术语突出显示的字符串作为前端的片段

  • 将类似的方法应用于完整文档中查询词的高度处理,doc.p.toString()...


附录

这是我写的以数组形式收集Solr“ q”和“ fq”术语的JS代码。请注意,Solrfq以字符串形式返回单项fq以数组形式返回多个项。

var q_arr = [];
var fq_arr = [];
var highlight_arr = [];
var snippets_arr = [];
var fq_vals = [];

if ((this.manager.store.get('q').value !== undefined) &&
    (this.manager.store.get('q').value !== '*:*')) {
    query = this.manager.store.get('q').value;
    q_arr.push(query);
    highlight_arr.push(query);
    console.log('q_arr:', q_arr, '| type:', typeof q_arr, '| length:', q_arr.length)
}

var doc_responseHeader = this.manager.response.responseHeader;
if (doc_responseHeader.params.fq !== undefined) {

    /* ONE "fq" (FILTER QUERY) TERM: */
    if (typeof doc_responseHeader.params.fq === 'string' ||
        doc_responseHeader.params.fq instanceof String) {
        fq_arr.push(doc_responseHeader.params.fq);
    }

    /* MORE THAN ONE "fq" (FILTER QUERY) TERM: */
    if  (typeof doc_responseHeader.params.fq === 'object' ||
        doc_responseHeader.params.fq instanceof Object) {

        for (var i = 0, l = doc_responseHeader.params.fq.length; i < l; i++) {
            fq_arr.push(doc_responseHeader.params.fq[i].toString());
        }
    }

    fq_vals = fq_arr.map(function(x){return x.replace(/keywords:/g, '');})
    console.log('fq_vals', fq_vals, '| type:', typeof fq_vals, '| length:', fq_vals.length)

    for (var i = 0, l = fq_vals.length; i < l; i++) {
        highlight_arr.push(fq_vals[i].toString());
    }
}