我有HTML文档,比方说:电子邮件。我想将它们存储在弹性搜索中并搜索HTML电子邮件的明文。
Elasticsearch也将索引所有HTML标记和属性。我不希望这样。我想搜索span
,如果它是纯文本,而不是html元素。例如,<span>span</span>
可能是一个匹配,但不是<span>some other content</span>
。
您是否建议在文档中存储HTML剥离字段和HTML字段?或者我应该在S3上存储HTML文档,而是在弹性搜索中留下剥离的HTML版本?它甚至有意义吗
老实说,我不知道如果弹性搜索索引HTML文档会发生什么,但我可以想象它还会索引div和spans以及所有属性。这些是我完全不寻找的东西。所以:在这里解决问题的任何建议都会很棒!
在我将文档存储在ES中之前,我检查文档类型是否存在索引。如果没有,我创建一个具有给定映射的集合。映射看起来像这样
{
"analysis": {
"analyzer": {
"htmlStripAnalyzer": {
"type": "custom",
"tokenizer": "standard",
"filter": "standard",
"char_filter": [
"html_strip"
]
}
}
},
"mappings": {
"${type}": {
"dynamic_templates": [
{
"_metadata": {
"path_match": "_metadata.*",
"mapping": {
"type": "keyword"
}
}
}
],
"properties": {
"_tags": {
"type": "nested",
"dynamic": true
}
}
}
}
}
警告:忽略现有的映射。这与我的意图无关。他们就在那里。
我正在用文档类型替换$ {type},让我们说emails
。
告诉ES不要将HTML内容编入索引会是什么样子?
答案 0 :(得分:6)
完整的测试用例:
DELETE /test
PUT /test
{
"settings": {
"analysis": {
"analyzer": {
"htmlStripAnalyzer": {
"type": "custom",
"tokenizer": "standard",
"filter": ["standard","lowercase"],
"char_filter": [
"html_strip"
]
}
}
}
},
"mappings": {
"test": {
"properties": {
"html": {
"type": "text",
"analyzer": "htmlStripAnalyzer"
}
}
}
}
}
POST /test/test/1
{
"html": "<td><tr>span<td></tr>"
}
POST /test/test/2
{
"html": "<span>whatever</span>"
}
POST /test/test/3
{
"html": "<html> <body> <h1 style=\"font-family: Arial\">Test</h1> <span>More test</span> </body> </html>"
}
POST /test/_search
{
"query": {
"match": {
"html": "span"
}
}
}
POST /test/_search
{
"query": {
"match": {
"html": "body"
}
}
}
POST /test/_search
{
"query": {
"match": {
"html": "more"
}
}
}
答案 1 :(得分:1)
默认情况下,如果在索引过程中找到任何新字段,Elasticsearch将动态添加新字段(请参阅this):
当Elasticsearch遇到文档中以前未知的字段时,它使用动态映射来确定字段的数据类型,并自动将新字段添加到类型映射中。
要禁用此行为(有关详细信息,请参阅doc),最简单的方法是将dynamic
置于 false (阻止自动创建)或严格(抛出异常并且不创建新文档)。在这种情况下,您需要明确地为要保留在_tags
部分内的标记写入映射,并预先解析HTML文档以仅将您感兴趣的标记提供给Elasticsearch。
因此,假设您有以下HTML文档:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>A simple example</title>
</head>
<body>
<div>
<p><span class="ref">A sentence I want to reference from this HTML document</span></p>
<p><span class="">Something less important</span></p>
</body>
</html>
你想要的第一件事是Elasticsearch中的静态映射,我会做以下(假设ref是一个字符串):
PUT html
{
"mappings": {
"test":{
"dynamic": "strict",
"properties": {
"ref":{
"type": "string"
}
}
}
}
现在,如果您尝试以这种方式添加文档,它将会成功:
PUT html/test/1
{
"ref": "A sentence I want to reference from this HTML document"
}
但这不会成功:
PUT html/test/2
{
"ref": "A sentence I want to reference from this HTML document",
"some_field": "Some field"
}
现在唯一剩下的就是解析HTML以检索“ref”字段,并创建上述查询(使用您喜欢的任何语言,Java,Python ......)
修改:实际上要存储HTML而不对其进行索引,在地图中您只需将index
设置为否(请参阅here):
"_tags": {
"type": "nested",
"dynamic": true,
"index": "no"
}