Elasticsearch 使用误区之六——富文本内容写入前不清洗

news2024/11/19 17:32:04

0、引言

在很多应用场景中,我们会将富文本内容(如 HTML 格式的网页内容)存储到 Elasticsearch 中,以实现全文检索。

然而,在实际使用过程中,我们可能会遇到一些问题,比如在检索时,HTML 标签被截断,或者检索结果中会显示部分 HTML 标签内容。这种现象不仅影响了检索体验,还可能对页面展示造成困扰。

本文将详细介绍如何解决这种富文本处理中的常见问题,帮助大家在使用 Elasticsearch 时更加高效地处理和展示富文本内容。

1、具体问题描述

Elasticsearch 所存储的数据包含但不限于:

  • 业务数据

  • 日志数据

  • 互联网采集数据

  • 其他数据 如果遇到互联网采集数据场景,Elasticsearch 的 content 字段极大可能需要存储的是富文本内容(HTML)。

遇到这种情况,咱们得非常的慎重。

不信,你看!如下 QQ 群群友出现的问题可见一斑。

91da735e4460cd43358a55a14913d80c.jpeg

827521b03d1210fac36f116f3b419258.png


什么问题呢?

在输入关键词进行检索时,可能会出现 HTML 标签被截断的情况,导致返回的结果中显示部分 HTML 标签内容。

这种情况对用户展示极为不友好。

那么,我们应该如何处理这种问题呢?

2、原因分析

Elasticsearch 本质上是一个文本检索引擎,它会对输入的文本进行分析、分词、索引,并对用户的搜索关键词进行相应匹配。

富文本(HTML)的特殊性在于,它不仅包含可见的文字,还包含大量的标记语言(如 <div>、<p>、<span> 等标签),这些标签在检索过程中可能会被 Elasticsearch 解析和处理,进而影响检索结果。

3、解决方案

针对这种情况,我们可以通过以下几个步骤来解决问题,确保检索结果更加干净、准确。

3.1. 清洗 HTML 内容

在将 HTML 内容写入 Elasticsearch 之前,最好先对其进行清洗。

清洗操作的目的是去除不必要的 HTML 标签,提取其中的有用文本信息。这可以通过编写自定义算法或使用 HTML 解析库来实现。

常用的 HTML 解析库包括 Jsoup、BeautifulSoup 等,其实采集团队或许已经做过处理。

如果公司采集团队和存储不是一个团队,建议深入交流一下字段细节内容。

3.2. 利用 Elasticsearch 的 HTML Strip 字符过滤器

Elasticsearch 提供了 html_strip  字符过滤器,可以用来自动去除 HTML 标签。

详细参见: 

https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-htmlstrip-charfilter.html

通过该过滤器,我们可以确保在索引过程中,HTML 标签不会被保留下来,只有纯文本内容会被处理和检索。

示例如下:

PUT my-index
{
  "settings": {
    "analysis": {
      "char_filter": {
        "html_strip": {
          "type": "html_strip"
        }
      },
      "analyzer": {
        "html_analyzer": {
          "type": "custom",
          "char_filter": [
            "html_strip"
          ],
          "tokenizer": "standard"
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "content": {
        "type": "text",
        "analyzer": "html_analyzer"
      }
    }
  }
解释:
  1. char_filter 部分定义了 HTML 过滤器,用于去除 HTML 标签。

  2. html_analyzer 是自定义的分析器,首先使用 html_strip 过滤器去除 HTML 标签,随后通过标准分词器 standard 进行分词和处理。

使用这个分析器进行索引和搜索时,HTML 标签会自动被过滤掉,确保只有纯文本内容参与搜索,进而避免了 HTML 标签截断的问题。

3.3 存储多版本的内容

为了兼顾搜索和展示,推荐在存储时将富文本内容存为两个字段:

  1. 原始 HTML 内容:用于在前端完整展示。

  2. 纯文本版本:用于索引和检索。

并且负责任告诉大家,真实互联网采集数据存储与展示场景,就得这么干

例如,我们可以在 Elasticsearch 中定义两种字段:

"mappings": {
  "properties": {
    "html_content": {
      "type": "text", 
      "index": false  // 不参与索引,仅用于展示
    },
    "cleaned_content": {
      "type": "text", 
      "analyzer": "html_analyzer"  // 纯文本版本,参与检索
    }
  }
}

这样,html_content 字段保留原始 HTML,用于页面回显;

而 cleaned_content 字段则经过清洗处理,专用于检索操作。

3.4. 通过前端处理回显内容

为了避免搜索结果中显示部分 HTML 标签的情况,我们可以在前端对回显的内容进行进一步处理:

  1. 使用前端的 HTML 渲染器,比如 Vue.js 或 React.js 的 v-html 和 dangerouslySetInnerHTML,确保内容正确渲染。

  2. 结合高亮功能,确保用户能够清晰地看到与查询关键词匹配的文本部分,而非 HTML 标签。

3.5. 关键词高亮功能

为了增强用户体验,Elasticsearch 提供了高亮显示功能,可以在返回结果时高亮显示与关键词匹配的部分。

通过以下 DSL 语句,我们可以实现对匹配部分的高亮显示:

POST my-index/_search
{
  "query": {
    "match": {
      "cleaned_content": "搜索关键词"
    }
  },
  "highlight": {
    "fields": {
      "cleaned_content": {}
    }
  }
}

这样,在展示时,只会高亮纯文本部分,HTML 标签将不会出现在检索结果中。

4、完整示例,彻底解决富文本存储

Elasticsearch 处理富文本内容(HTML)的方案如下:

4.1 创建索引并配置 HTML 过滤器

如前方案探讨所述,我们首先创建一个新的索引,使用 Elasticsearch 的 html_strip 过滤器来去除 HTML 标签,并配置两个字段:一个存储清洗后的纯文本内容用于检索,另一个存储原始 HTML 内容用于展示。

PUT html_content_index
{
  "settings": {
    "analysis": {
      "char_filter": {
        "html_strip": {
          "type": "html_strip"
        }
      },
      "analyzer": {
        "html_analyzer": {
          "type": "custom",
          "char_filter": [
            "html_strip"
          ],
          "tokenizer": "standard"
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "html_content": {
        "type": "text",
        "index": false  // 原始 HTML 内容不参与索引,仅用于展示
      },
      "cleaned_content": {
        "type": "text",
        "analyzer": "html_analyzer"  // 清洗后用于检索的纯文本
      }
    }
  }
}

4.2 向索引中写入数据

我们将两种不同的内容分别写入到 html_content 和 cleaned_content 字段。

html_content 保存的是原始 HTML,而 cleaned_content 保存的是清洗后的纯文本。

POST /html_content_index/_doc
{
  "html_content": "<p>这是一段关于<strong>Elasticsearch</strong>的文章。</p>",
  "cleaned_content": "这是一段关于 Elasticsearch 的文章。"
}

在这个例子中,html_content 保留了 HTML 标签,而 cleaned_content 则去除了 HTML 标签,只保留了纯文本内容。

4.3 进行搜索并返回高亮结果

接下来,我们对 cleaned_content 字段进行全文检索,同时启用高亮功能,确保关键词匹配部分能够在前端得到突出显示。

GET /html_content_index/_search
{
  "query": {
    "match": {
      "cleaned_content": "Elasticsearch"
    }
  },
  "highlight": {
    "fields": {
      "cleaned_content": {}
    }
  }
}

返回结果示例如下:

5140743c83b4f4754dbb23193b81a877.png

{
  "took": 34,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 0.2876821,
    "hits": [
      {
        "_index": "html_content_index",
        "_id": "INbUKZIBSx0oX-FAHL8S",
        "_score": 0.2876821,
        "_source": {
          "html_content": "<p>这是一段关于<strong>Elasticsearch</strong>的文章。</p>",
          "cleaned_content": "这是一段关于 Elasticsearch 的文章。"
        },
        "highlight": {
          "cleaned_content": [
            "这是一段关于 <em>Elasticsearch</em> 的文章。"
          ]
        }
      }
    ]
  }
}

4.4 前端展示:结合原始 HTML 和高亮结果

在前端,我们可以使用 html_content 字段来展示完整的 HTML 内容,而使用 highlight 字段来突出显示用户搜索的关键词。这样,用户既可以看到完整的富文本格式的内容,又能清楚地识别出匹配的关键词。

伪代码:

<!-- 显示原始 HTML 内容 -->
<div v-html="html_content"></div>

<!-- 高亮显示匹配的关键词 -->
<div v-html="highlighted_cleaned_content"></div>

4.5 预处理 HTML 清洗

除了在 Elasticsearch 中使用 html_strip 过滤器,我们还可以在存入 Elasticsearch 之前预先清洗 HTML 内容。

以下是使用 Java 的 Jsoup 库来清洗 HTML 的示例:

import org.jsoup.Jsoup;

public class HTMLCleaner {
    public static String cleanHTML(String html) {
        return Jsoup.parse(html).text();  // 将 HTML 内容转换为纯文本
    }
}

在保存数据到 Elasticsearch 之前,先调用 cleanHTML 方法去除不必要的 HTML 标签,然后将纯文本存入 cleaned_content 字段。

5、小结

在处理富文本内容时,合理的清洗和过滤是避免 HTML 标签影响检索结果的关键。

处理 HTML 内容的关键在于:清洗 + 分离存储 + 高亮展示

通过预处理富文本内容,使用 html_strip 过滤器,以及前端渲染和高亮展示,可以有效地避免 HTML 标签截断问题,从而确保用户获得干净、准确的搜索体验。

富文本不做处理直接写入是 Elasticsearch 使用中的常见误区之一,希望本文提供的解决方案能够帮助大家在日常工作中更好地应对类似问题。

更多推荐

  1. Elasticsearch 使用误区之一——将 Elasticsearch 视为关系数据库!

  2.   Elasticsearch 使用误区之二——频繁更新文档

  3. Elasticsearch 使用误区之三——分片设置不合理

  4. Elasticsearch 使用误区之四——不合理的使用 track_total_hits

  5. Elasticsearch 使用误区之五——单次请求获取大量数据

  6.    《一本书讲透 Elasticsearch》读者群的创新之路

594914e0a437769ac88bb0c1641c6059.jpeg

更短时间更快习得更多干货!

和全球2000+ Elastic 爱好者一起精进!

elastic6.cn——ElasticStack进阶助手

e50fc5c4ee467f9c921c3130b51dd601.gif

抢先一步学习进阶干货!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2183190.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

通信工程学习:什么是FTP文件传输协议

FTP&#xff1a;文件传输协议 FTP&#xff08;File Transfer Protocol&#xff0c;文件传输协议&#xff09;是一种用于在网络上交换文件的协议&#xff0c;它定义了文件传输时使用的命令和响应。作为最古老的互联网协议之一&#xff0c;FTP至今仍被广泛使用&#xff0c;并在网…

Elasticsearch:使用 LLM 实现传统搜索自动化

作者&#xff1a;来自 Elastic Han Xiang Choong 这篇简短的文章是关于将结构化数据上传到 Elastic 索引&#xff0c;然后将纯英语查询转换为查询 DSL 语句&#xff0c;以使用特定过滤器和范围搜索特定条件。完整代码位于此 Github repo 中。 首先&#xff0c;运行以下命令安装…

8639 折半插入排序

### 思路 折半插入排序是一种改进的插入排序算法&#xff0c;通过二分查找来确定插入位置&#xff0c;从而减少比较次数。每次插入时&#xff0c;先用二分查找找到插入位置&#xff0c;然后将元素插入到正确的位置。 ### 伪代码 1. 读取输入的待排序关键字个数n。 2. 读取n个待…

8. Bug 与 Error

计算机程序中的缺陷通常被称为 bug。把它们想象成偶然爬进我们工作中的小东西&#xff0c;会让程序员感觉良好。当然&#xff0c;实际上是我们自己把它们放进去的。 如果程序是思想的结晶&#xff0c;我们可以将错误大致分为思想混乱造成的错误和将思想转化为代码时引入错误造成…

帝都程序猿十二时辰

前言 2019年度国产剧《长安十二时辰》火了&#xff0c;其口碑榜首、节奏紧凑、贴合原著、电影质感&#xff0c;都是这部剧的亮点。而最令人震撼的还是剧中对大唐盛世的还原&#xff0c;长安街坊的市容市貌、长安百姓的生活日常、长安风情的美轮美奂……而关于十二时辰的话题也接…

基础算法--双指针【概念+图解+题解+解释】

更多精彩内容..... &#x1f389;❤️播主の主页✨&#x1f618; Stark、-CSDN博客 本文所在专栏&#xff1a; 数据结构与算法_Stark、的博客-CSDN博客 其它专栏&#xff1a; 学习专栏C语言_Stark、的博客-CSDN博客 项目实战C系列_Stark、的博客-CSDN博客​​​​​​ 座右铭&a…

【算法竞赛】堆

堆是一种树形结构,树的根是堆顶,堆顶始终保持为所有元素的最优值。 有最大堆和最小堆,最大堆的根节点是最大值,最小堆的根节点是最小值。 本节都以最小堆为例进行讲解。 堆一般用二叉树实现,称为二叉堆。 二叉堆的典型应用有堆排序和优先队列。 二叉堆的概念 二叉堆是一棵…

Mybatis-Plus新花样(二)

多种插件 Mybatis-plus给我们提供了各种各样的插件&#xff0c;方便我们快捷开发。 一. 插件配置 Configuration public class MybatisPlusConfig {Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor new MybatisPlusInter…

CMIS5.2_光模块切应用(Application Selection and Instantiation)

目录 重要概念 DP配置、应用声明、应用码的区别 Control Set Provision 和 Commission ApplyDPInit 和 ApplyImmediate 判断应用是否切换成功 以800G光模块的3个应用对应的DP配置举例 1*800G应用&#xff1a; 2*400G应用&#xff1a; 8*100G应用&#xff1a; 应用声明…

ControlGAN:Controllable Text-to-Image Generation

1 研究目的 当前的生成网络通常是不可控的&#xff0c;这意味着如果用户更改句子的某些单词&#xff0c;合成图像将与原始文本生成的合成图像显着不同&#xff1b;当给定的文本描述&#xff08;例如颜色&#xff09;发生变化时&#xff0c;鸟类的相应视觉属性被修改&#xff0c…

我博客网站又遭受CC攻击了,记录一下

2024.9.29凌晨4点攻击开始&#xff0c;攻击目标是我的图床tc.zeruns.tech和博客blog.zeruns.tech&#xff0c;图床用的cdn是多吉云融合CDN&#xff0c;流量被刷了20GB左右就触发峰值关闭CDN了&#xff0c;HTTPS请求次数被刷了1.1亿次&#xff0c;因为设置了QPS&#xff0c;实际…

Oracle bbed编译安装及配置

1. 什么是bbed &#xff1f; Oracle Block Brower and EDitor Tool,是一个可以对oracle data block进行查看&#xff0c;编辑修改的内置工具。对于bbed&#xff0c;oracle本身是不提供支持的。 2. 如何编译bbed环境&#xff1f; 10g版本&#xff1a; 1) 编译bbed cd $ORACL…

【网络基础】网络常识快速入门知识清单,看这篇文章就够了

&#x1f490;个人主页&#xff1a;初晴~ 在现在这个高度智能化的时代&#xff0c;网络几乎已经成为了空气一般无处不在。移动支付、网上购物、网络游戏、视频网站都离不开网络。你能想象如果没有网络的生活将会变成什么样吗&#x1f914; 然而如此对于如此重要的网络&#xf…

深度学习500问——Chapter17:模型压缩及移动端部署(2)

文章目录 17.4.6 低秩分解 17.4.7 总体压缩效果评价指标有哪些 17.4.8 几种轻量化网络结构对比 17.4.9 网络压缩未来研究方向有哪些 17.5 目前有哪些深度学习模型优化加速方法 17.5.1 模型优化加速方法 17.5.2 TensorRT加速原理 17.5.3 TensorRT如何优化重构模型 17.5.4 Tensor…

Unity中Mesh多种网格绘制模式使用方法参考

Unity中MeshFilter中的Mesh默认情况下使用MeshTopology.Trigangles类型绘制网格&#xff0c;就是通常的绘制三角形网格&#xff0c;实际上Mesh有五种绘制模式&#xff0c;对应MeshTopology的枚举&#xff0c;分别是 Triangles网格由三角形构成。Quads网格由四边形构成。Lines网…

多线程——认识线程(Thread)

目录 前言 一、第一个多线程程序 1.程序编写 2.介绍jconsole 二、创建线程 1.继承Thread类 ①重写run方法 ②重写run方法&#xff0c;使用匿名内部类 2.实现Runnable接口 ①重写run方法 ②重写run方法&#xff0c;使用匿名内部类 ③使用 lambda 表达式 三、多线程…

【吊打面试官系列-MySQL面试题】为表中得字段选择合适得数据类型

大家好&#xff0c;我是锋哥。今天分享关于【为表中得字段选择合适得数据类型】面试题&#xff0c;希望对大家有帮助&#xff1b; 为表中得字段选择合适得数据类型 字段类型优先级: 整形>date,time>enum,char>varchar>blob,text 优先考虑数字类型&#xff0c;其次是…

c++类与对象二

文章目录 C类与对象二类的实例化类对象内存大小计算this指针特性 C类与对象二 类的实例化 用类创建对象的过程&#xff0c;称之为类的实例化 类是对对象进行描述的&#xff0c;限定了类有哪些成员&#xff0c;定义一个类并没有开辟内存空间。例如需要学生填写的个人表格&…

js 如何获取当日零点整的时间戳

最近遇到个问题需要取当日的零点整的时间戳去存取日程 上代码&#xff1a; const timestr new Date().setHours(0, 0, 0, 0) console.log(timestr) 效果展示&#xff1a; Tips&#xff1a;除了 Java 以外的语言需要除以1000 具体视情况而定 Java、js的时间戳都是毫秒级的…

每日一练:腐烂的橘子

994. 腐烂的橘子 - 力扣&#xff08;LeetCode&#xff09; 题目要求&#xff1a; 在给定的 m x n 网格 grid 中&#xff0c;每个单元格可以有以下三个值之一&#xff1a; 值 0 代表空单元格&#xff1b;值 1 代表新鲜橘子&#xff1b;值 2 代表腐烂的橘子。 每分钟&#xf…