Apache Solr 提取,根据查询突出显示 HTML 个元素,过滤查询词
Apache Solr extract, highlight HTML elements based on query, filter query terms
更新。 (+18d) 编辑标题并提供解决原始问题的答案。
tl/dr
我正在索引 HTML 页面并将 <p>...</p>
内容转储为搜索查询 return 的片段。但是,我不想要/不需要所有这些内容(只是查询匹配文本周围的上下文)。
背景
在我的[经典]架构中有了这些,
<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-tags 中,例如<p>Sentence 1.</p>
, <p>Sentence 1.</p>
, ...
问题
如何单独索引它们?我的理由是我想显示搜索结果目标周围的上下文片段(而不是整个 p-tagged 内容)。
此外,在 Linux grep
命令中我们可以,例如, return 匹配行前后的一行 (-C1
,语境、论点)。我们可以在这里做类似的事情吗?
即,如果 Solr 查询匹配在句子 2 中,则该片段将包含句子 1-3?
我尝试将唯一 ID 分配给 p-elements(<p id="a">...</p> <p id="b">...</p>
但我刚在 Solr 中得到这个,
"p":["a Sentence 1. b Sentence 2. Sentence d 3. Sentence d 4. ..."]
更新 [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, "|").split("|");
其中 doc.p
是一个 Solr 字段(在 schema.xml
中定义)对应于索引 HTML p 元素 (
...
) 文本。
- 详情:见Split string into sentences in javascript
突出显示那些查询字词
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"></font>')
}
var doc_p_hl = replacer(doc.p.toString(), query);
- 详情:见
使用那些术语突出显示的字符串作为前端的片段
在完整文档中应用类似的方法来突出显示查询词,doc.p.toString()
...
附录
这是我编写的用于在数组中收集 Solr“q”和“fq”项的 JS 代码。请注意,Solr returns 单个 fq
作为字符串,多个 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());
}
}
更新。 (+18d) 编辑标题并提供解决原始问题的答案。
tl/dr
我正在索引 HTML 页面并将 <p>...</p>
内容转储为搜索查询 return 的片段。但是,我不想要/不需要所有这些内容(只是查询匹配文本周围的上下文)。
背景
在我的[经典]架构中有了这些,
<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-tags 中,例如<p>Sentence 1.</p>
, <p>Sentence 1.</p>
, ...
问题
如何单独索引它们?我的理由是我想显示搜索结果目标周围的上下文片段(而不是整个 p-tagged 内容)。
此外,在 Linux
grep
命令中我们可以,例如, return 匹配行前后的一行 (-C1
,语境、论点)。我们可以在这里做类似的事情吗?即,如果 Solr 查询匹配在句子 2 中,则该片段将包含句子 1-3?
我尝试将唯一 ID 分配给 p-elements(<p id="a">...</p> <p id="b">...</p>
但我刚在 Solr 中得到这个,
"p":["a Sentence 1. b Sentence 2. Sentence d 3. Sentence d 4. ..."]
更新 [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, "|").split("|");
其中
doc.p
是一个 Solr 字段(在schema.xml
中定义)对应于索引 HTML p 元素 (...
) 文本。- 详情:见Split string into sentences in javascript
突出显示那些查询字词
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"></font>') } var doc_p_hl = replacer(doc.p.toString(), query);
- 详情:见
- 详情:见
使用那些术语突出显示的字符串作为前端的片段
在完整文档中应用类似的方法来突出显示查询词,
doc.p.toString()
...
附录
这是我编写的用于在数组中收集 Solr“q”和“fq”项的 JS 代码。请注意,Solr returns 单个 fq
作为字符串,多个 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());
}
}