大数据ELK四:Lucene的美文搜索案例

美文搜索案例

一、需求

在资料中的文章文件夹中,有很多的文本文件。这里面包含了一些非常有趣的软文。而我们想要做的事情是,通过搜索一个关键字就能够找到哪些文章包含了这些关键字。例如:搜索「hadoop」,就能找到hadoop相关的文章。

需求分析

要实现以上需求,我们有以下两种办法:

  • 用户输入搜索关键字,然后我们挨个读取文件,并查找文件中是否包含关键字
  • 我们先挨个读取文件,对文件的文本进行分词(例如:按标点符号),然后建立索引,用户输入关键字,根据之前建立的索引,搜索关键字。

很明显,第二种方式要比第一种效果好得多,性能也好得多。所以,我们下面就使用Lucene来建立索引,然后根据索引来进行检索。

二、准备工作

1、创建IDEA项目

此处在IDEA中的工程模型如下:

2、创建父工程

groupId

cn.it

artifactId

es_parent

3、添加lucene模块

groupId

cn.it

artifactId

lucene_op

4、导入Maven依赖

导入依赖到lucene_op的pom.xml

<dependencies>
    <!-- lucene核心类库 -->
    <dependency>
        <groupId>org.apache.lucene</groupId>
        <artifactId>lucene-core</artifactId>
        <version>8.4.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.lucene</groupId>
        <artifactId>lucene-analyzers-common</artifactId>
        <version>8.4.0</version>
    </dependency>
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.6</version>
    </dependency>
    <dependency>
        <groupId>com.jianggujin</groupId>
        <artifactId>IKAnalyzer-lucene</artifactId>
        <version>8.0.0</version>
    </dependency>

</dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

5、创建包和类

  • 在java目录创建 cn.it.lucene 包结构
  • 创建BuildArticleIndex类

6、导入文章数据

  1. 在 lucene_op 模块下创建名为 data 的目录,用来存放文章文件
  2. 在 lucene_op 模块下创建名为 index 的目录,用于存放最后生成的索引文件
  3. 将资料/文章目录下的txt文件复制到 data 目录中

三、建立索引库

1、实现步骤

  • 构建分词器(StandardAnalyzer)
  • 构建文档写入器配置(IndexWriterConfig)
  • 构建文档写入器(IndexWriter,注意:需要使用Paths来)
  • 读取所有文件构建文档
  • 文档中添加字段

字段名

类型

说明

file_name

TextFiled

文件名字段,需要在索引文档中保存文件名内容

content

TextFiled

内容字段,只需要能被检索,但无需在文档中保存

path

StoredFiled

路径字段,无需被检索,只需要在文档中保存即可

  • 写入文档
  • 关闭写入器

2、参考代码

package cn.it.lucene;


import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import org.apache.commons.io.FileUtils;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.FSDirectory;

public class BuildArticleIndex {
    public static void main(String[] args) throws IOException {
        // 1. 构建分词器(StandardAnalyzer)
        StandardAnalyzer standardAnalyzer = new StandardAnalyzer();

        // 2. 构建文档写入器配置(IndexWriterConfig)
        IndexWriterConfig indexWriterConfig = new IndexWriterConfig(standardAnalyzer);

        // 3. 构建文档写入器(IndexWriter)
        IndexWriter indexWriter = new IndexWriter(
            FSDirectory.open(Paths.get("E:\\project\\java\\elk\\es_parent\\lucene_op\\index")), indexWriterConfig);

        // 4. 读取所有文件构建文档
        File articleDir = new File("E:\\project\\java\\elk\\es_parent\\lucene_op\\data");
        File[] fileList = articleDir.listFiles();

        for (File file : fileList) {
            // 5. 文档中添加字段
            Document docuemnt = new Document();
            docuemnt.add(new TextField("file_name", file.getName(), Field.Store.YES));
            docuemnt.add(new TextField("content", FileUtils.readFileToString(file, "UTF-8"), Field.Store.NO));
            docuemnt.add(new StoredField("path", file.getAbsolutePath() + "/" + file.getName()));
            // 6. 写入文档
            indexWriter.addDocument(docuemnt);
        }

        // 7. 关闭写入器
        indexWriter.close();
    }
}

3、执行效果

四、关键字查询

1、需求

输入一个关键字“心”,根据关键字查询索引库中是否有匹配的文档

2、准备工作

  • 前提:基于文章文本文件,已经生成好了索引
  • 在cn.it.lucene包下创建一个类KeywordSearch

3、开发步骤

  • 使用DirectoryReader.open构建索引读取器
  • 构建索引查询器(IndexSearcher)
  • 构建词条(Term)和词条查询(TermQuery)
  • 执行查询,获取文档
  • 遍历打印文档(可以使用IndexSearch.doc根据文档ID获取到文档)
  • 关键索引读取器

4、参考代码

package cn.it.lucene;

import java.io.IOException;
import java.nio.file.Paths;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.FSDirectory;

public class KeywordSearch {
    public static void main(String[] args) throws IOException {
        // 1. 构建索引读取器
        IndexReader indexReader = DirectoryReader.open(FSDirectory.open(Paths.get("E:\\project\\java\\elk\\es_parent\\lucene_op\\index")));

        // 2. 构建索引查询器
        IndexSearcher indexSearcher = new IndexSearcher(indexReader);

        // 3. 执行查询,获取文档
        TermQuery termQuery = new TermQuery(new Term("content", "心"));

        TopDocs topDocs = indexSearcher.search(termQuery, 50);
        ScoreDoc[] scoreDocArrary = topDocs.scoreDocs;

        // 4. 遍历打印文档
        for (ScoreDoc scoreDoc : scoreDocArrary) {
            int docId = scoreDoc.doc;
            Document document = indexSearcher.doc(docId);

            System.out.println("文件名:" + document.get("file_name") + " 路径:" + document.get("path"));
        }

        indexReader.close();

    }
}

5、执行效果

五、搜索词语问题

上述代码,都是一个字一个字的搜索,但如果搜索一个词,例如:“情愿”,我们会发现,我们什么都搜索不出来。所以,接下来,我们还需要来解决搜索一个词的问题。

六、分词器与中文分词器

分词器是指将一段文本,分割成为一个个的词语的动作。例如:按照停用词进行分隔(的、地、啊、吧、标点符号等)。我们之前在代码中使用的分词器是Lucene中自带的分词器。这个分词器对中文很不友好,只是将一个一个字分出来,所以,就会从后出现上面的问题——无法搜索词语。

所以,基于该背景,我们需要使用跟适合中文的分词器。中文分词器也有不少,例如:

  • Jieba分词器
  • IK分词器
  • 庖丁分词器
  • Smarkcn分词器

等等。此处,我们使用比较好用的IK分词器来进行分词。

IK已经实现好了Lucene的分词器:https://github.com/wks/ik-analyzer

| IKAnalyzer是一个开源的,基于java语言开发的轻量级的中文分词工具包。从2006年12月推出1.0版开始,IKAnalyzer已经推出了3个大版本。最初,它是以开源项目Luence为应用主体的,结合词典分词和文法分析算法的中文分词组件。新版本的 IKAnalyzer3.0则发展为面向Java的公用分词组件,独立于Lucene项目,同时提供了对Lucene的默认优化实现。 IKAnalyzer3.0特性: 采用了特有的“正向迭代最细粒度切分算法“,支持细粒度和最大词长两种切分模式;具有83万字/秒(1600KB/S)的高速处理能力。 采用了多子处理器分析模式,支持:英文字母、数字、中文词汇等分词处理,兼容韩文、日文字符 优化的词典存储,更小的内存占用。支持用户词典扩展定义 针对Lucene全文检索优化的查询分析器IKQueryParser(作者吐血推荐);引入简单搜索表达式,采用歧义分析算法优化查询关键字的搜索排列组合,能极大的提高Lucene检索的命中率。 |

|:----|

七、使用IK分词器重构案例

1、准备工作

添加Maven依赖

<dependency>
    <groupId>com.jianggujin</groupId>
    <artifactId>IKAnalyzer-lucene</artifactId>
    <version>8.0.0</version>
</dependency>

 创建BuildArticleIndexByIkAnalyzer类

2、实现步骤

把之前生成的索引文件删除,然后将之前使用的StandardAnalyzer修改为IKAnalyzer。然后重新生成索引。

3、参考代码

package cn.it.lucene;

import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import org.apache.commons.io.FileUtils;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.FSDirectory;
import org.wltea.analyzer.lucene.IKAnalyzer;

public class BuildArticleIndexByIkAnalyzer {
    public static void main(String[] args) throws IOException {
        // 1. 构建分词器(StandardAnalyzer)
        IKAnalyzer ikAnalyzer = new IKAnalyzer();

        // 2. 构建文档写入器配置(IndexWriterConfig)
        IndexWriterConfig indexWriterConfig = new IndexWriterConfig(ikAnalyzer);

        // 3. 构建文档写入器(IndexWriter)
        IndexWriter indexWriter = new IndexWriter(
            FSDirectory.open(Paths.get("E:\\project\\java\\elk\\es_parent\\lucene_op\\index")), indexWriterConfig);

        // 4. 读取所有文件构建文档
        File articleDir = new File("E:\\project\\java\\elk\\es_parent\\lucene_op\\data");
        File[] fileList = articleDir.listFiles();

        for (File file : fileList) {
            // 5. 文档中添加字段
            Document docuemnt = new Document();
            docuemnt.add(new TextField("file_name", file.getName(), Field.Store.YES));
            docuemnt.add(new TextField("content", FileUtils.readFileToString(file, "UTF-8"), Field.Store.NO));
            docuemnt.add(new StoredField("path", file.getAbsolutePath() + "/" + file.getName()));
            // 6. 写入文档
            indexWriter.addDocument(docuemnt);
        }

        // 7. 关闭写入器
        indexWriter.close();
    }
}

4、执行效果

5、问题

通过使用IK分词器进行分词,我们发现,现在我们的程序可以搜索词语了。但如果我们输入一句话:人生是一条河,我们想要搜索出来与其相关的文章。应该如何实现呢?

八、句子搜索

在cn.it.lucene 包下创建一个SentenceSearch类

1、实现步骤

要实现搜索句子,其实是将句子进行分词后,再进行搜索。我们需要使用QueryParser类来实现。通过QueryParser可以指定分词器对要搜索的句子进行分词。

2、参考代码

package cn.it.lucene;

import java.io.IOException;
import java.nio.file.Paths;
import java.text.ParseException;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.FSDirectory;
import org.wltea.analyzer.lucene.IKAnalyzer;

public class SentenceSearch {
    public static void main(String[] args) throws IOException {
        // 1. 构建索引读取器
        IndexReader indexReader = DirectoryReader.open(FSDirectory.open(Paths.get("D:\\project\\51.V8.0_NoSQL_MQ\\ElasticStack\\code\\es_parent\\lucene_op\\index")));

        // 2. 构建索引查询器
        IndexSearcher indexSearcher = new IndexSearcher(indexReader);

        // 3. 执行查询,获取文档
        QueryParser queryParser = new QueryParser("content", new IKAnalyzer());

        TopDocs topDocs = null;
        try {
            topDocs = indexSearcher.search(queryParser.parse("人生是一条河"), 50);
        } catch (org.apache.lucene.queryparser.classic.ParseException e) {
            e.printStackTrace();
        }
        ScoreDoc[] scoreDocArrary = topDocs.scoreDocs;

        // 4. 遍历打印文档
        for (ScoreDoc scoreDoc : scoreDocArrary) {
            int docId = scoreDoc.doc;
            Document document = indexSearcher.doc(docId);

            System.out.println("文件名:" + document.get("file_name") + " 路径:" + document.get("path"));
        }

        indexReader.close();

    }
}

3、执行效果

原文地址:https://cloud.tencent.com/developer/article/1887231

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


文章浏览阅读5.3k次,点赞10次,收藏39次。本章详细写了mysql的安装,环境的搭建以及安装时常见的问题和解决办法。_mysql安装及配置超详细教程
文章浏览阅读1.8k次,点赞50次,收藏31次。本篇文章讲解Spark编程基础这门课程的期末大作业,主要围绕Hadoop基本操作、RDD编程、SparkSQL和SparkStreaming编程展开。_直接将第4题的计算结果保存到/user/root/lisi目录中lisipi文件里。
文章浏览阅读7.8k次,点赞9次,收藏34次。ES查询常用语法目录1. ElasticSearch之查询返回结果各字段含义2. match 查询3. term查询4. terms 查询5. range 范围6. 布尔查询6.1 filter加快查询效率的原因7. boosting query(提高查询)8. dis_max(最佳匹配查询)9. 分页10. 聚合查询【内含实际的demo】_es查询语法
文章浏览阅读928次,点赞27次,收藏18次。
文章浏览阅读1.1k次,点赞24次,收藏24次。作用描述分布式协调和一致性协调多个节点的活动,确保一致性和顺序。实现一致性、领导选举、集群管理等功能,确保系统的稳定和可靠性。高可用性和容错性Zookeeper是高可用的分布式系统,通过多个节点提供服务,容忍节点故障并自动进行主从切换。作为其他分布式系统的高可用组件,提供稳定的分布式协调和管理服务,保证系统的连续可用性。配置管理和动态更新作为配置中心,集中管理和分发配置信息。通过订阅机制,实现对配置的动态更新,以适应系统的变化和需求的变化。分布式锁和并发控制。
文章浏览阅读1.5k次,点赞26次,收藏29次。为贯彻执行集团数字化转型的需要,该知识库将公示集团组织内各产研团队不同角色成员的职务“职级”岗位的评定标准;
文章浏览阅读1.2k次,点赞26次,收藏28次。在安装Hadoop之前,需要进行以下准备工作:确认操作系统:Hadoop可以运行在多种操作系统上,包括Linux、Windows和Mac OS等。选择适合你的操作系统,并确保操作系统版本符合Hadoop的要求。安装Java环境:Hadoop是基于Java开发的,因此需要先安装和配置Java环境。确保已经安装了符合Hadoop版本要求的Java Development Kit (JDK),并设置好JAVA_HOME环境变量。确认硬件要求:Hadoop是一个分布式系统,因此需要多台计算机组成集群。
文章浏览阅读974次,点赞19次,收藏24次。# 基于大数据的K-means广告效果分析毕业设计 基于大数据的K-means广告效果分析。
文章浏览阅读1.7k次,点赞6次,收藏10次。Hadoop入门理论
文章浏览阅读1.3w次,点赞28次,收藏232次。通过博客和文献调研整理的一些农业病虫害数据集与算法。_病虫害数据集
文章浏览阅读699次,点赞22次,收藏7次。ZooKeeper使用的是Zab(ZooKeeper Atomic Broadcast)协议,其选举过程基于一种名为Fast Leader Election(FLE)的算法进行。:每个参与选举的ZooKeeper服务器称为一个“Follower”或“Candidate”,它们都有一个唯一的标识ID(通常是一个整数),并且都知道集群中其他服务器的ID。总之,ZooKeeper的选举机制确保了在任何时刻集群中只有一个Leader存在,并通过过半原则保证了即使部分服务器宕机也能维持高可用性和一致性。
文章浏览阅读10w+次,点赞62次,收藏73次。informatica 9.x是一款好用且功能强大的数据集成平台,主要进行各类数据库的管理操作,是使用相当广泛的一款ETL工具(注: ETL就是用来描述将数据从源端经过抽取(extract)、转换(transform)、加载(load)到目的端的过程)。本文主要为大家图文详细介绍Windows10下informatica powercenter 9.6.1安装与配置步骤。文章到这里就结束了,本人是在虚拟机中装了一套win10然后在此基础上测试安装的这些软件,因为工作学习要分开嘛哈哈哈。!!!!!_informatica客户端安装教程
文章浏览阅读7.8w次,点赞245次,收藏2.9k次。111个Python数据分析实战项目,代码已跑通,数据可下载_python数据分析项目案例
文章浏览阅读1.9k次,点赞61次,收藏64次。TDH企业级一站式大数据基础平台致力于帮助企业更全面、更便捷、更智能、更安全的加速数字化转型。通过数年时间的打磨创新,已帮助数千家行业客户利用大数据平台构建核心商业系统,加速商业创新。为了让大数据技术得到更广泛的使用与应用从而创造更高的价值,依托于TDH强大的技术底座,星环科技推出TDH社区版(Transwarp Data Hub Community Edition)版本,致力于为企业用户、高校师生、科研机构以及其他专业开发人员提供更轻量、更简单、更易用的数据分析开发环境,轻松应对各类人员数据分析需求。_星环tdh没有hive
文章浏览阅读836次,点赞21次,收藏19次。
文章浏览阅读1k次,点赞21次,收藏15次。主要介绍ETL相关工作的一些概念和需求点
文章浏览阅读1.4k次。本文以Android、java为开发技术,实现了一个基于Android的博物馆线上导览系统 app。基于Android的博物馆线上导览系统 app的主要使用者分为管理员和用户,app端:首页、菜谱信息、甜品信息、交流论坛、我的,管理员:首页、个人中心、用户管理、菜谱信息管理、菜谱分类管理、甜品信息管理、甜品分类管理、宣传广告管理、交流论坛、系统管理等功能。通过这些功能模块的设计,基本上实现了整个博物馆线上导览的过程。
文章浏览阅读897次,点赞19次,收藏26次。1.背景介绍在当今的数字时代,数据已经成为企业和组织中最宝贵的资源之一。随着互联网、移动互联网和物联网等技术的发展,数据的产生和收集速度也急剧增加。这些数据包括结构化数据(如数据库、 spreadsheet 等)和非结构化数据(如文本、图像、音频、视频等)。这些数据为企业和组织提供了更多的信息和见解,从而帮助他们做出更明智的决策。业务智能(Business Intelligence,BI)...
文章浏览阅读932次,点赞22次,收藏16次。也就是说,一个类应该对自己需要耦合或调用的类知道的最少,类与类之间的关系越密切,耦合度越大,那么类的变化对其耦合的类的影响也会越大,这也是我们面向对象设计的核心原则:低耦合,高内聚。优秀的架构和产品都是一步一步迭代出来的,用户量的不断增大,业务的扩展进行不断地迭代升级,最终演化成优秀的架构。其根本思想是强调了类的松耦合,类之间的耦合越弱,越有利于复用,一个处在弱耦合的类被修改,不会波及有关系的类。缓存,从操作系统到浏览器,从数据库到消息队列,从应用软件到操作系统,从操作系统到CPU,无处不在。
文章浏览阅读937次,点赞22次,收藏23次。大数据可视化是关于数据视觉表现形式的科学技术研究[9],将数据转换为图形或图像在屏幕上显示出来,并进行各种交互处理的理论、方法和技术。将数据直观地展现出来,以帮助人们理解数据,同时找出包含在海量数据中的规律或者信息,更多的为态势监控和综合决策服务。数据可视化是大数据生态链的最后一公里,也是用户最直接感知数据的环节。数据可视化系统并不是为了展示用户的已知的数据之间的规律,而是为了帮助用户通过认知数据,有新的发现,发现这些数据所反映的实质。大数据可视化的实施是一系列数据的转换过程。