搜索引擎主题模型优化(第四章基于lucene的索引与搜索4.1什么是Lucene全文检索)
优采云 发布时间: 2022-02-13 15:22搜索引擎主题模型优化(第四章基于lucene的索引与搜索4.1什么是Lucene全文检索)
第四章 基于Lucene的索引和搜索
4.1什么是Lucene全文搜索
Lucene 是 Jakarta Apache 的一个开源项目。是一个用Java编写的全文索引引擎工具包,可以方便地嵌入到各种应用程序中,实现应用程序的全文索引/检索功能。
4.2 Lucene原理分析
4.2.1 全文检索的实现机制
Lucene的API接口设计比较通用,输入输出结构与数据库表==>记录==>字段非常相似,所以很多传统的应用文件、数据库等都可以很方便的映射到Lucene的存储结构和界面中间。
总体来说:Lucene可以看做是一个支持全文索引的数据库系统。
索引数据源:doc(field1,field2...) doc(field1,field2...)
\索引器/
_____________
| Lucene 索引|
--------------
/searcher 结果输出:Hits(doc(field1,field2)doc(field1...))
Document:一个需要被索引的“单元”,一个Document由多个字段组成
领域:领域
Hits:查询结果集,由匹配的 Documents 组成
4.2.2 Lucene 索引效率
通常在书后附一张关键词索引表(例如:北京:12、34页,上海:3、77页……),可以帮助读者找到相关的页码。内容比较快。和数据库索引的原理可以大大提高查询速度是一样的,想象一下书后面的索引搜索速度比翻页翻翻内容要快多少倍……而原因为什么索引是高效的,另一个原因是它是排序的。检索系统的核心是排序问题。
由于数据库索引不是为全文索引而设计的,所以当使用 like "%keyword%" 时,数据库索引不起作用。使用like查询时,搜索过程变成了类似翻页书的遍历过程,所以对于收录模糊查询的数据库服务,LIKE对性能的伤害很大。如果需要对多个关键词进行模糊匹配:like "%keyword1%" and like "%keyword2%" ...效率可想而知。因此,建立高效检索系统的关键是建立类似于技术索引的反向索引机制。在按排序顺序存储数据源(如多个文章)的同时,还有一个排序好的关键词列表用于存储关键词==>文章的映射关系, 使用这样的映射关系索引:[关键词==>文章where 关键词出现@>个数,出现次数(甚至包括位置:起始偏移量,结束偏移量),出现频率],检索过程是将模糊查询转化为可以利用索引的多个精确查询的逻辑组合的过程。这大大提高了多个 关键词 查询的效率。因此,全文检索问题归结为排序问题。这大大提高了多个 关键词 查询的效率。因此,全文检索问题归结为排序问题。这大大提高了多个 关键词 查询的效率。因此,全文检索问题归结为排序问题。
由此可以看出,模糊查询相对于数据库的精确查询是一个非常不确定的问题,这也是大多数数据库对全文检索支持有限的原因。Lucene的核心特点是通过特殊的索引结构实现了传统数据库不擅长的全文索引机制,并提供了扩展接口,方便针对不同应用进行定制。
可以通过下表对比数据库的模糊查询:
Lucene全文索引引擎数据库
索引 数据源中的数据通过全文索引一一建立,创建逆索引。对于 LIKE 查询,传统的数据索引根本没用。数据需要在方便的逐条记录基础上进行 GREP 样式的模糊匹配,这比索引搜索慢几个数量级。
匹配效果通过词元(term)进行匹配,通过语言分析接口的实现,可以实现对中文等非英文的支持。使用:像 "%net%" 也匹配荷兰,
多个关键词的模糊匹配:使用like "%com%net%":无法匹配倒序的词序。。
匹配度有匹配度算法,匹配度(相似度)比较高的结果排在第一位。没有匹配程度的控制:例如,如果记录中有5个单词和1次出现net,结果是一样的。
结果输出通过特殊的算法,输出匹配度最好的前100个结果,以缓冲区类型小批量读取结果集。返回所有结果集。当匹配的条目很多(比如上万个)时,需要大量的内存来存储这些临时结果集。
可定制性通过不同的语言分析接口实现,可轻松定制符合应用需求的索引规则(包括对中文的支持) 无接口或接口复杂,无法定制
结论 高负载的模糊查询应用需要对模糊查询规则负责,索引数据量比较大,使用率低,模糊匹配规则简单,或者模糊查询所需数据量少
4.2.3 中文分词机制
对于中文,全文索引首先要解决语言分析的问题。对于英语来说,句子中的单词自然是用空格隔开的,但亚洲语言中日韩句子中的单词是逐字逐句的。,所有,首先,如果要按“单词”来索引句子,如何对单词进行分词是个大问题。
首先,不能使用单个字符(si-gram)作为索引单位,否则查找“上海”时,无法匹配“上海”。但是一句话:“北京*敏*感*词*”,电脑是怎么按照中国人的语言习惯来划分的?“北京*敏*感*词*”还是“北京*敏*感*词*”?计算机要能够根据语言习惯进行切分,往往需要机器有比较丰富的词库,才能更准确地识别句子中的单词。另一种解决方案是使用自动切分算法:按照2-gram(bigram)方法对单词进行切分,例如:“Beijing Tiananmen” ==> “Beijing Jingtian'anmen”。这样查询的时候,是否在查询“
自动切分最大的优点是没有词汇维护成本,实现简单。缺点是索引效率低,但对于中小型应用,基于2-grams的分割就足够了。基于 2 元素分割的索引大小一般与源文件大小相似,而对于英文,索引文件一般与原创文件只有 30%-40% 的差异。
自动分词
实现很简单 实现很复杂
Query增加了查询分析的复杂度,适合实现更复杂的查询语法规则
存储效率索引是冗余的,索引几乎和原来的一样大。该索引是有效的,大约是原创大小的 30%。
维护成本 无词汇维护成本 词汇维护成本非常高:中文、日文、韩文等语言需要单独维护。
还需要包括词频统计等。
适用领域 嵌入式系统:运行环境资源有限
分布式系统:没有词汇同步问题
多语言环境:专业的搜索引擎,查询和存储效率要求高,无需词汇维护成本
4.3 Lucene和Spider的结合
首先构造一个Index类来实现内容的索引。
代码分析如下:
<STRONG>package</STRONG> news; /** * 新闻搜索引擎 * 计算机99630 沈晨 * 版本1.0 */ <STRONG>import</STRONG> java.io.IOException; <STRONG>import</STRONG> org.apache.lucene.analysis.cn.ChineseAnalyzer; <STRONG>import</STRONG> org.apache.lucene.document.Document; <STRONG>import</STRONG> org.apache.lucene.document.Field; <STRONG>import</STRONG> org.apache.lucene.index.IndexWriter; <STRONG>public</STRONG> <STRONG>class</STRONG> Index { IndexWriter _writer = <STRONG>null</STRONG>; Index() <STRONG>throws</STRONG> Exception { _writer = <STRONG>new</STRONG> IndexWriter("c:\\News\\index", <STRONG>new</STRONG> ChineseAnalyzer(), <STRONG>true</STRONG>); } /** * 把每条新闻加入索引中 * @param url 新闻的url * @param title 新闻的标题 * @throws java.lang.Exception */ <STRONG>void</STRONG> AddNews(String url, String title) <STRONG>throws</STRONG> Exception { Document _doc = <STRONG>new</STRONG> Document(); _doc.add(Field.Text("title", title)); _doc.add(Field.UnIndexed("url", url)); _writer.addDocument(_doc); } /** * 优化并且清理资源 * @throws java.lang.Exception */ <STRONG>void</STRONG> close() <STRONG>throws</STRONG> Exception { _writer.optimize(); _writer.close(); } }
然后构造一个HTML解析类来索引bot程序采集的新闻内容。
代码分析如下:
<STRONG>package</STRONG> news; /** * 新闻搜索引擎 * 计算机99630 沈晨 * 版本1.0 */ <STRONG>import</STRONG> java.util.Iterator; <STRONG>import</STRONG> java.util.Vector; <STRONG>import</STRONG> com.heaton.bot.HTMLPage; <STRONG>import</STRONG> com.heaton.bot.HTTP; <STRONG>import</STRONG> com.heaton.bot.Link; <STRONG>public</STRONG> <STRONG>class</STRONG> HTMLParse { HTTP _http = <STRONG>null</STRONG>; <STRONG>public</STRONG> HTMLParse(HTTP http) { _http = http; } /** * 对Web页面进行解析后建立索引 */ <STRONG>public</STRONG> <STRONG>void</STRONG> start() { <STRONG>try</STRONG> { HTMLPage _page = <STRONG>new</STRONG> HTMLPage(_http); _page.open(_http.getURL(), <STRONG>null</STRONG>); Vector _links = _page.getLinks(); Index _index = <STRONG>new</STRONG> Index(); Iterator _it = _links.iterator(); <STRONG>int</STRONG> n = 0; <STRONG>while</STRONG> (_it.hasNext()) { Link _link = (Link) _it.next(); String _herf = input(_link.getHREF().trim()); String _title = input(_link.getPrompt().trim()); _index.AddNews(_herf, _title); n++; } System.out.println("共扫描到" + n + "条新闻"); _index.close(); } <STRONG>catch</STRONG> (Exception ex) { System.out.println(ex); } } /** * 解决java中的中文问题 * @param str 输入的中文 * @return 经过解码的中文 */ <STRONG>public</STRONG> <STRONG>static</STRONG> String input(String str) { String temp = <STRONG>null</STRONG>; <STRONG>if</STRONG> (str != <STRONG>null</STRONG>) { <STRONG>try</STRONG> { temp = <STRONG>new</STRONG> String(str.getBytes("ISO8859_1")); } <STRONG>catch</STRONG> (Exception e) { } } <STRONG>return</STRONG> temp; } }
4.4 小节
在进行海量数据搜索时,使用纯数据库技术可能会非常痛苦。速度将是一个很大的瓶颈。所以本章提出使用全文搜索引擎Lucene进行索引和搜索。
***,还结合具体代码来说明如何将Lucene全文搜索引擎和Spider程序结合起来实现新闻搜索的功能。
第 5 章 基于 Tomcat 的 Web 服务器
5.1 什么是基于 Tomcat 的 Web 服务器
Web服务器是为网络中的信息发布、数据查询、数据处理等诸多应用搭建基础平台的服务器。Web 服务器的工作原理:网页处理分为三个步骤。步骤一,网络浏览器向特定服务器发送网页请求;步骤2,Web服务器接收到网页请求后,将搜索请求的网页发送给Web浏览器;第三步,网络服务器接收请求的网页并显示出来。
Tomcat 是一个开源的、基于 Java 的 Web 应用程序软件容器,它运行 servlet 和 JSP Web 应用程序。Tomcat 由 Apache-Jakarta 子项目支持,并由开源 Java 社区的志愿者维护。Tomcat Server 是按照 servlet 和 JSP 规范实现的,因此可以说 Tomcat Server 也实现了 Apache-Jakarta 规范,优于大多数商业应用软件服务器。
5.2 用户界面设计
5.3.1客户端设计
一个好的查询界面很重要,比如谷歌就以简洁的查询界面着称。我在设计时也充分考虑了实用性和简洁性。
5.3.2服务器设计
它主要由JavaTM Servlet 技术实现。用户通过 GET 方法从客户端向服务器提交查询条件。服务器通过Tomcat servlet容器接受并分析提交的参数,然后调用lucene开发包进行搜索操作。*** 将搜索结果以 HTTP 消息包的形式发送给客户端,完成一次搜索操作。
服务器servlet程序的结构如下:
实现的关键代码如下:
<p><STRONG>public</STRONG> <STRONG>void</STRONG> Search(String qc, PrintWriter out) <STRONG>throws</STRONG> Exception { // 从索引目录创建索引 IndexSearcher _searcher = <STRONG>new</STRONG> IndexSearcher("c:\\news\\index"); // 创建标准分析器 Analyzer analyzer = <STRONG>new</STRONG> ChineseAnalyzer(); // 查询条件 String line = qc; // Query是一个抽象类 Query query = QueryParser.parse(line, "title", analyzer); out.println(""); out.println("搜索结果"); out.println(""); out.println("" + "" + "新闻搜索引擎:" + "" + "" + "" ); out.println("搜索关键字:" + query.toString("title") + ""); Hits hits = _searcher.search(query); out.println(" 总共找到" + hits.length() + "条新闻"); <STRONG>final</STRONG> <STRONG>int</STRONG> HITS_PER_PAGE = 10; <STRONG>for</STRONG> (<STRONG>int</STRONG> start = 0; start