lucene

 倒排索引:

在这里插入图片描述

 

Lucene是一套用于全文检索和搜寻的开源程序库,由Apache软件基金会支持和提供

Lucene提供了一个简单却强大的应用程序接口(API),能够做全文索引和搜寻,在Java开发环境里Lucene是一个成熟的免费开放源代码工具

Lucene并不是现成的搜索引擎产品,但可以用来制作搜索引擎产品

官网:http://lucene.apache.org/

 Lucene、Solr、Elasticsearch关系

Lucene:底层的API,工具包

Solr:基于Lucene开发的企业级的搜索引擎产品

Elasticsearch:基于Lucene开发的企业级的搜索引擎产品

 

 Lucene的基本使用
使用Lucene的API来实现对索引的增(创建索引)、删(删除索引)、改(修改索引)、查(搜索数据)。

 创建索引
创建索引的流程

在这里插入图片描述
文档Document:数据库中一条具体的记录

字段Field:数据库中的每个字段

目录对象Directory:物理存储位置

写出器的配置对象:需要分词器和lucene的版本

 

添加依赖:

<properties>
    <lunece.version>4.10.2</lunece.version>

</properties>
<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    <!-- lucene核心库 -->
    <dependency>
        <groupId>org.apache.lucene</groupId>
        <artifactId>lucene-core</artifactId>
        <version>${lunece.version}</version>
    </dependency>
    <!-- Lucene的查询解析器 -->
    <dependency>
        <groupId>org.apache.lucene</groupId>
        <artifactId>lucene-queryparser</artifactId>
        <version>${lunece.version}</version>
    </dependency>
    <!-- lucene的默认分词器库 -->
    <dependency>
        <groupId>org.apache.lucene</groupId>
        <artifactId>lucene-analyzers-common</artifactId>
        <version>${lunece.version}</version>
    </dependency>
    <!-- lucene的高亮显示 -->
    <dependency>
        <groupId>org.apache.lucene</groupId>
        <artifactId>lucene-highlighter</artifactId>
        <version>${lunece.version}</version>
    </dependency>
    <dependency>
            <groupId>com.janeluo</groupId>
            <artifactId>ikanalyzer</artifactId>
            <version>2012_u6</ version>
        </dependency>
</dependencies>

 //1 创建文档对象
//2 创建存储目录
//3 创建分词器
//4 创建索引写入器的配置对象
//5 创建索引写入器对象
//6 将文档交给索引写入器
//7 提交
//8 关闭

 

创建只有一条文档的文件

 // 创建索引
    @Test
    public void testCreate() throws Exception{
        //1 创建文档对象
        Document document = new Document();
        // 创建并添加字段信息。参数:字段的名称、字段的值、是否存储,这里选Store.YES代表存储到文档列表。Store.NO代表不存储
        document.add(new StringField("id", "1", Field.Store.YES));
        // 这里我们title字段需要用TextField,即创建索引又会被分词。StringField会创建索引,但是不会被分词
        document.add(new TextField("title", "谷歌地图之父跳槽facebook", Field.Store.YES));

        //2 索引目录类,指定索引在硬盘中的位置
        Directory directory = FSDirectory.open(new File("d:\\indexDir"));
        //3 创建分词器对象
        Analyzer analyzer = new StandardAnalyzer();
        //4 索引写出工具的配置对象
        IndexWriterConfig conf = new IndexWriterConfig(Version.LATEST, analyzer);
        //5 创建索引的写出工具类。参数:索引的目录和配置信息
        IndexWriter indexWriter = new IndexWriter(directory, conf);

        //6 把文档交给IndexWriter
        indexWriter.addDocument(document);
        //7 提交
        indexWriter.commit();
        //8 关闭
        indexWriter.close();
 }

创建多条文档的文件

 @Test
    public void testCreate2() {
        try {
            ArrayList<Document> documents = new ArrayList<Document>();

            Document document = new Document();
            document.add(new StringField("id","1",Field.Store.YES));
            document.add(new TextField("title","谷歌地图之父跳槽facebook",Field.Store.YES));
            documents.add(document);

            Document document2 = new Document();
            document2.add(new StringField("id","2",Field.Store.YES));
            document2.add(new TextField("title","谷歌地图之父加盟FaceBook",Field.Store.YES));
            documents.add(document2);

            Document document3 = new Document();
            document3.add(new StringField("id","3",Field.Store.YES));
            document3.add(new TextField("title","谷歌地图创始人拉斯离开谷歌加盟Facebook",Field.Store.YES));
            documents.add(document3);

            Document document4 = new Document();
            document4.add(new StringField("id","4",Field.Store.YES));
            document4.add(new TextField("title","谷歌地图之父跳槽Facebook与Wave项目取消有关",Field.Store.YES));
            documents.add(document4);

            Document document5 = new Document();
            document5.add(new StringField("id","5",Field.Store.YES));
            document5.add(new TextField("title","谷歌地图之父拉斯加盟社交网站Facebook",Field.Store.YES));
            documents.add(document5);

            FSDirectory dir = FSDirectory.open(new File("d:/lucenedata"));

            IndexWriterConfig conf = new IndexWriterConfig(Version.LATEST, new IKAnalyzer());
            conf.setOpenMode(IndexWriterConfig.OpenMode.CREATE);
            IndexWriter indexWriter = new IndexWriter(dir, conf);

            indexWriter.addDocuments(documents);
            indexWriter.commit();
            indexWriter.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

查询代码:

 @Test
    public void testSearch() throws Exception {
        // 索引目录对象
        Directory directory = FSDirectory.open(new File("d:\\indexDir"));
        // 索引读取工具
        IndexReader reader = DirectoryReader.open(directory);
        // 索引搜索工具
        IndexSearcher searcher = new IndexSearcher(reader);

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

        // 搜索数据,两个参数:查询条件对象要查询的最大结果条数
        // 返回的结果是 按照匹配度排名得分前N名的文档信息(包含查询到的总条数信息、所有符合条件的文档的编号信息)。
        TopDocs topDocs = searcher.search(query, 10);
        // 获取总条数
        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);
        }
    }

高亮显示

// 高亮显示
    @Test
    public void testHighlighter() throws Exception {
        // 目录对象
        Directory directory = FSDirectory.open(new File("d:/lucenedata"));
        // 创建读取工具
        IndexReader reader = DirectoryReader.open(directory);
        // 创建搜索工具
        IndexSearcher searcher = new IndexSearcher(reader);

        QueryParser parser = new QueryParser("title", new IKAnalyzer());
        Query query = parser.parse("谷歌地图");

        // 格式化器
        Formatter formatter = new SimpleHTMLFormatter("<body>", "</body>");
        QueryScorer scorer = new QueryScorer(query);
        // 准备高亮工具
        Highlighter highlighter = new Highlighter(formatter, scorer);
        // 搜索
        TopDocs topDocs = searcher.search(query, 10);
        System.out.println("本次搜索共" + topDocs.totalHits + "条数据");

        ScoreDoc[] scoreDocs = topDocs.scoreDocs;
        for (ScoreDoc scoreDoc : scoreDocs) {
            // 获取文档编号
            int docID = scoreDoc.doc;
            Document doc = reader.document(docID);
            System.out.println("id: " + doc.get("id"));

            String title = doc.get("title");
            // 用高亮工具处理普通的查询结果,参数:分词器,要高亮的字段的名称,高亮字段的原始值
            String hTitle = highlighter.getBestFragment(new IKAnalyzer(), "title", title);

            System.out.println("title: " + hTitle);
            // 获取文档的得分
            System.out.println("得分:" + scoreDoc.score);
        }

    }

排序

 // 排序
    @Test
    public void testSortQuery() throws Exception {
        // 目录对象
        Directory directory = FSDirectory.open(new File("d:/lucenedata"));
        // 创建读取工具
        IndexReader reader = DirectoryReader.open(directory);
        // 创建搜索工具
        IndexSearcher searcher = new IndexSearcher(reader);

        QueryParser parser = new QueryParser("title", new IKAnalyzer());
        Query query = parser.parse("谷歌地图");

        // 创建排序对象,需要排序字段SortField,参数:字段的名称、字段的类型、是否反转如果是false,升序。true降序
        Sort sort = new Sort(new SortField("id", SortField.Type.LONG, true));
        // 搜索
        TopDocs topDocs = searcher.search(query, 10,sort);
        System.out.println("本次搜索共" + topDocs.totalHits + "条数据");

        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"));
        }
    }

分页

  // 分页
    @Test
    public void testPageQuery() throws Exception {
        // 实际上Lucene本身不支持分页。因此我们需要自己进行逻辑分页。我们要准备分页参数:
        int pageSize = 2;// 每页条数
        int pageNum = 3;// 当前页码
        int start = (pageNum - 1) * pageSize;// 当前页的起始条数
        int end = start + pageSize;// 当前页的结束条数(不能包含)

        // 目录对象
        Directory directory = FSDirectory.open(new File("d:lucenedata" ));
        // 创建读取工具
        IndexReader reader = DirectoryReader.open(directory);
        // 创建搜索工具
        IndexSearcher searcher = new IndexSearcher(reader);

        QueryParser parser = new QueryParser("title", new IKAnalyzer());
        Query query = parser.parse("谷歌地图");

        // 创建排序对象,需要排序字段SortField,参数:字段的名称、字段的类型、是否反转如果是false,升序。true降序
        Sort sort = new Sort(new SortField("id", SortField.Type.LONG, false));
        // 搜索数据,查询0~end条
        TopDocs topDocs = searcher.search(query, end,sort);
        System.out.println("本次搜索共" + topDocs.totalHits + "条数据");

        ScoreDoc[] scoreDocs = topDocs.scoreDocs;
        for (int i = start; i < end; i++) {
            ScoreDoc scoreDoc = scoreDocs[i];
            // 获取文档编号
            int docID = scoreDoc.doc;
            Document doc = reader.document(docID);
            System.out.println("id: " + doc.get("id"));
            System.out.println("title: " + doc.get("title"));
        }
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值