Lucene入门

1. Lucene概述

  • 什么是Lucene

    • Lucene是一套用于全文检索和搜寻的开源程序库,由Apache软件基金会支持和提供
    • Lucene提供了一个简单却强大的应用程序接口(API),能够做全文索引和搜寻,在Java开发环境里Lucene是一个成熟的免费开放源代码工具
    • Lucene并不是现成的搜索引擎产品,但可以用来制作搜索引擎产品
    • 官网 http://lucene.apache.org/
  • 什么是全文检索

  • Lucene下载及版本问题
    • 目前最新的版本是6.x系列,但是大多数企业中依旧使用4.x版本,比较稳定
  • Lucene与Solr的关系
    • Lucene:一套实现了全文检索的底层API
    • Solr:基于Lucene开发的企业级搜索应用服务器

2、Lucene的基本使用

  • 2.1、准备工作
    • 创建 Maven工程
    • 引入Maven依赖
      • 单元测试:junit
      • 核心库:lucene-core
      • 分词器:lucene-analyzers-common
      • 查询解析器:lucene-queryparser
      • 高亮显示:lucene-highlighter
<dependencies>
        <!-- Junit单元测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <!-- lucene核心库 -->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-core</artifactId>
            <version>4.10.2</version>
        </dependency>
        <!-- Lucene的查询解析器 -->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-queryparser</artifactId>
            <version>4.10.2</version>
        </dependency>
        <!-- lucene的默认分词器库 -->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-analyzers-common</artifactId>
            <version>4.10.2</version>
        </dependency>
        <!-- lucene的高亮显示 -->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-highlighter</artifactId>
            <version>4.10.2</version>
        </dependency>
        <!-- IK分词器 -->
        <dependency>
            <groupId>com.janeluo</groupId>
            <artifactId>ikanalyzer</artifactId>
            <version>2012_u6</version>
        </dependency>

    </dependencies>
    <build>
        <plugins>
            <!-- java编译插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.2</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>
  • 2.2 创建索引
    • 创建索引的流程:
      创建索引的流程:
  • 2.3 代码实现
//索引的创建分三步
@Test
public void testCreate() throws Exception{
    //1. 创建文档对象
    Document document = new Document();
    /*
     * 1.1 创建并添加字段信息。
     * 参数:字段的名称、字段的值、是否存储,
     * 这里选Store.YES代表存储到文档列表。Store.NO代表不存储
     */
    document.add(new StringField("id", "1", Store.YES));
    /*
     * 这里我们title字段需要用TextField,即创建索引又会被分词。
     * StringField会创建索引,但是不会被分词
     */
    document.add(new TextField("title", "2", Store.YES));

    //2. 创建索引写入器
    /*
     * 2.1 索引目录类,指定索引在硬盘中的位置
     */
    Directory d = FSDirectory.open(new File("luceneIndex"));
    /*
     * 2.2  创建分词器对象
     */
    Analyzer analyzer = new StandardAnalyzer();
    /*
     * 2.3 索引写出工具的配置对象
     */
    IndexWriterConfig conf = new IndexWriterConfig(Version.LATEST, analyzer);
    /*
     * 2.4  创建索引的写出工具类。参数:索引的目录和配置信息
     */
    IndexWriter writer = new IndexWriter(d, conf);

    //3. 把文档交给IndexWriter
    writer.addDocument(document);
    // 提交
    writer.commit();
    // 关闭
    writer.close();
}
  • 2.4 使用工具查看索引(Luke 查看工具 略)
  • 2.5 创建索引的API详解

    • Document(文档)
      • 文档对象,是一条原始的数据
    • Field(字段类)

      • 一个Document中可以有很多个不同的字段,每一个字段都是一个Field类的对象。

      • 一个Document中的字段其类型是不确定的,因此Field类就提供了各种不同的子类,来对应这些不同类型的字段。
        IndexableField

    这些子类有一些不同的特性:
    1)DoubleField、FloatField、IntField、LongField、StringField、TextField这些子类一定会被创建索引。但是不一定会被存储到文档列表。要通过构造函数中的参数Store来指定:如果Store.YES代表存储,Store.NO代表不存储
    2)TextField即创建索引,又会被分词。StringField会创建索引,但是不会被分词。如果不分词,会造成整个字段作为一个词条,除非用户完全匹配,否则搜索不到
    3)StoreField一定会被存储,但是一定不创建索引,StoredField可以创建各种数据类型的字段
    .
    问题1:如何确定一个字段是否需要存储?
    如果一个字段要显示到最终的结果中,那么一定要存储,否则就不存储

    问题2:如何确定一个字段是否需要创建索引?
    如果要根据这个字段进行搜索,那么这个字段就必须创建索引。

    问题3:如何确定一个字段是否需要分词?
    前提是这个字段首先要创建索引。然后如果这个字段的值是不可分割的,那么就不需要分词。例如:ID

    • Directory( 目录类)– 指定索引要存储的位置

      • FSDirectory:文件系统目录,会把索引库指向本地磁盘。
        特点:速度略慢,但是比较安全
      • RAMDirectory:内存目录,会把索引库保存在内存。
        特点:速度快,但是不安全
    • Analyzer (分词器)

    • IK分词器
    • IndexWriterConfig
      • 设置配置信息:Lucene的版本和分词器类型
      • 设置是否清空索引库中的数据
    • IndexWriter : 索引写出工具,作用就是 实现对索引的增(创建索引)、删(删除索引)、改(修改索引)
  • 2.6 可以一次创建一个,也可以批量创建索引
//索引的创建分三步
@Test
public void testMultiCreate() throws Exception{

    // 创建文档的集合
    Collection<Document> docs = new ArrayList<>();
    // 创建文档对象
    Document document1 = new Document();
    document1.add(new StringField("id", "1", Store.YES));
    document1.add(new TextField("title", "谷歌地图之父跳槽facebook", Store.YES));
    docs.add(document1);
    // 创建文档对象
    Document document2 = new Document();
    document2.add(new StringField("id", "2", Store.YES));
    document2.add(new TextField("title", "谷歌地图之父加盟FaceBook", Store.YES));
    docs.add(document2);
    // 创建文档对象
    Document document3 = new Document();
    document3.add(new StringField("id", "3", Store.YES));
    document3.add(new TextField("title", "谷歌地图创始人拉斯离开谷歌加盟Facebook", Store.YES));
    docs.add(document3);
    // 创建文档对象
    Document document4 = new Document();
    document4.add(new StringField("id", "4", Store.YES));
    document4.add(new TextField("title", "谷歌地图之父跳槽Facebook与Wave项目取消有关", Store.YES));
    docs.add(document4);
    // 创建文档对象
    Document document5 = new Document();
    document5.add(new StringField("id", "5", Store.YES));
    document5.add(new TextField("title", "谷歌地图之父拉斯加盟社交网站Facebook", Store.YES));
    docs.add(document5);


    // 索引目录类,指定索引在硬盘中的位置
    Directory directory = FSDirectory.open(new File("indexDir"));
    // 引入IK分词器
    Analyzer analyzer = new IKAnalyzer();
    // 索引写出工具的配置对象
    IndexWriterConfig conf = new IndexWriterConfig(Version.LATEST, analyzer);
    // 设置打开方式:OpenMode.APPEND 会在索引库的基础上追加新索引。
    //OpenMode.CREATE会先清空原来数据,再提交新的索引
    conf.setOpenMode(OpenMode.CREATE);

    // 创建索引的写出工具类。参数:索引的目录和配置信息
    IndexWriter indexWriter = new IndexWriter(directory, conf);
    // 把文档集合交给IndexWriter
    indexWriter.addDocuments(docs);
    // 提交
    indexWriter.commit();
    // 关闭
    indexWriter.close();

}
  • 2.7 查询索引
@Test
public void testQuery() throws IOException, ParseException{
    /*
 * 1. 索引目录对象
 */
Directory directory = FSDirectory.open(new File("indexDir"));
/*
 * 2. 索引读取工具
 */
IndexReader reader = DirectoryReader.open(directory);
/*
 * 3. 索引搜索工具
 */
IndexSearcher searcher = new IndexSearcher(reader);

/*
 * 4. 创建查询解析器,两个参数:默认要查询的字段的名称,分词器
 */
QueryParser parser = new QueryParser("title", new IKAnalyzer());
/*
 * 5. 创建查询对象
 */
Query query = parser.parse("谷歌地图之父拉斯");

/*
 * 6.  搜索数据,两个参数:查询条件对象要查询的最大结果条数
 * 返回的结果是 按照匹配度排名得分前N名的文档信息(包含查询到的总条数信息、所有符合条件的文档的编号信息)。
 */
TopDocs topDocs = searcher.search(query, 10);
/*
 * 7. 解析结果 获取总条数
 */
System.out.println("本次搜索共找到" + topDocs.totalHits + "条数据");
// 获取得分文档对象(ScoreDoc)数组.SocreDoc中包含:文档的编号、文档的得分
ScoreDoc[] scoreDocs = topDocs.scoreDocs;
for (ScoreDoc scoreDoc : scoreDocs) {
    // 取出文档编号
    int docID = scoreDoc.doc;
    // 根据编号去找文档
    Document doc = reader.document(docID);
    System.out.println("id: " + doc.get("id"));
    System.out.println("title: " + doc.get("title"));
    // 取出文档得分
    System.out.println("得分: " + scoreDoc.score);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值