美文网首页搜索引擎入门
搜索学习入门--Lucene初体验(Lucene索引的增删改查)

搜索学习入门--Lucene初体验(Lucene索引的增删改查)

作者: _时间海 | 来源:发表于2018-06-08 09:55 被阅读0次

    Lucene是一个开放源代码的全文检索引擎工具包,它提供了完整的查询引擎和索引引擎,开发人员可以方便的在目标系统中实现全文检索。Lucene的核心使用的是基于倒排索引的,并且实现了实现了分块索引。下面,先来体验一下Lucene对索引的增删改查功能。Lucene存储对象是以document为存储单元,对象中相关的属性值则存放到Field中。

    第一步:引入依赖

    <!-- Lucene核心 -->
    <dependency>
        <groupId>org.apache.lucene</groupId>
        <artifactId>lucene-core</artifactId>
        <version>4.7.2</version>
    </dependency>
    
    <!-- Lucene搜索查询相关 -->
    <dependency>
        <groupId>org.apache.lucene</groupId>
        <artifactId>lucene-queryparser</artifactId>
        <version>4.7.2</version>
    </dependency>
    
    <!-- Lucene分词器相关 -->
    <dependency>
        <groupId>org.apache.lucene</groupId>
        <artifactId>lucene-analyzers-common</artifactId>
        <version>4.7.2</version>
    </dependency>
    

    第二步:建立索引

    这里使用标准分词器建立5个Document的索引

    import org.apache.lucene.analysis.Analyzer;
    import org.apache.lucene.analysis.standard.StandardAnalyzer;
    import org.apache.lucene.document.*;
    import org.apache.lucene.index.*;
    import org.apache.lucene.store.Directory;
    import org.apache.lucene.store.LockObtainFailedException;
    import org.apache.lucene.store.SimpleFSDirectory;
    import org.apache.lucene.util.Version;
    
    import java.io.File;
    import java.io.IOException;
    
    /**
     * created by yuyufeng on 2017/11/13.
     */
    public class LuceneIndexDemo {
        public static void main(String[] args) {
            // Lucene Document的域名
            String fieldName = "blog";
            String text = "";
            // 建立5条索引
            text = "10月11日杭州云栖大会上,马云表达了对新建成的阿里巴巴全球研究院—阿里巴巴达摩院的愿景,希望达摩院二十年内成为世界第一大经济体,服务世界二十亿人,创造一亿个工作岗位。";
            doIndex(fieldName, text);
            text = "中国互联网界,阿里巴巴被认为是技术实力最弱的公司。我确实不懂技术,承认不懂技术不丢人,不懂装懂才丢人。";
            doIndex(fieldName, text);
            text = "阿里巴巴未来二十年的目标是打造世界第五大经济体,不是我们狂妄,而是世界需要这么一个经济体,也一定会有这么一个经济体。";
            doIndex(fieldName, text);
            text = "达摩院一定也必须要超越英特尔,必须超越微软,必须超越IBM,因为我们生于二十一世纪,我们是有机会后发优势的。";
            doIndex(fieldName, text);
            text = "阿里巴巴有很多争议,似乎无处不在,我还真想不出有什么东西是我们不做的。互联网是一种思想,是一种技术革命,不应该有界限。跨界乐趣无穷。我觉得阿里巴巴的跨界还不错";
            doIndex(fieldName, text);
    
    
        }
    
        private static void doIndex(String fieldName, String text) {
            // 实例化IKAnalyzer分词器
            Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_47);
    
            Directory directory = null;
            IndexWriter iwriter;
            try {
                // 索引目录
                directory = new SimpleFSDirectory(new File("D://test/lucene_index"));
    
                // 配置IndexWriterConfig
                IndexWriterConfig iwConfig = new IndexWriterConfig(Version.LUCENE_47, analyzer);
                iwConfig.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
                iwriter = new IndexWriter(directory, iwConfig);
                // 写入索引
                Document doc = new Document();
                Long id = System.currentTimeMillis();
                doc.add(new StringField("ID", id+"", Field.Store.YES));
                doc.add(new TextField(fieldName, text, Field.Store.YES));
                iwriter.addDocument(doc);
                iwriter.close();
                System.out.println("建立索引成功:" + id);
            } catch (CorruptIndexException e) {
                e.printStackTrace();
            } catch (LockObtainFailedException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (directory != null) {
                    try {
                        directory.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

    运行结果
    建立索引成功:1510579712099
    建立索引成功:1510579712355
    建立索引成功:1510579712512
    建立索引成功:1510579712743
    建立索引成功:1510579712912

    查看索引文件:运行之后,打开我们存放索引的文件夹,你会看到如下文件列表结构:

    这里写图片描述

    第三步:搜索查询

    import org.apache.lucene.analysis.Analyzer;
    import org.apache.lucene.analysis.standard.StandardAnalyzer;
    import org.apache.lucene.document.Document;
    import org.apache.lucene.index.DirectoryReader;
    import org.apache.lucene.index.IndexReader;
    import org.apache.lucene.index.IndexWriterConfig;
    import org.apache.lucene.queryparser.classic.ParseException;
    import org.apache.lucene.queryparser.classic.QueryParser;
    import org.apache.lucene.search.IndexSearcher;
    import org.apache.lucene.search.Query;
    import org.apache.lucene.search.ScoreDoc;
    import org.apache.lucene.search.TopDocs;
    import org.apache.lucene.store.Directory;
    import org.apache.lucene.store.SimpleFSDirectory;
    import org.apache.lucene.util.Version;
    
    import java.io.File;
    import java.io.IOException;
    
    /**
     * created by yuyufeng on 2017/11/13.
     */
    public class LuceneSearchDemo {
        public static void main(String[] args) {
    
            // Lucene Document的域名
            String fieldName = "blog";
            Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_47);
            Directory directory = null;
            IndexReader ireader = null;
            IndexSearcher isearcher;
    
            try {
                //索引目录
                directory = new SimpleFSDirectory(new File("D://test/lucene_index"));
                // 配置IndexWriterConfig
                IndexWriterConfig iwConfig = new IndexWriterConfig(Version.LUCENE_47, analyzer);
                iwConfig.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
    
                // 搜索过程**********************************
                // 实例化搜索器
                ireader = DirectoryReader.open(directory);
                isearcher = new IndexSearcher(ireader);
    
                String keyword = "达摩院";
                // 使用QueryParser查询分析器构造Query对象
                QueryParser qp = new QueryParser(Version.LUCENE_47, fieldName, analyzer);
                qp.setDefaultOperator(QueryParser.OR_OPERATOR);  // and or 跟数据库查询语法类似
                Query query = qp.parse(keyword);
                System.out.println("Query = " + query);
    
                // 搜索相似度最高的5条记录
                TopDocs topDocs = isearcher.search(query, 5);
                System.out.println("命中:" + topDocs.totalHits);
                // 遍历输出结果
                ScoreDoc[] scoreDocs = topDocs.scoreDocs;
                for (int i = 0; i < topDocs.totalHits; i++) {
                    Document targetDoc = isearcher.doc(scoreDocs[i].doc);
                    System.out.println("内容:" + targetDoc.toString());
                }
            } catch (ParseException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (ireader != null) {
                    try {
                        ireader.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (directory != null) {
                    try {
                        directory.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    
        }
    }
    

    **keyword= :"达摩院"
    运行结果

    Query = blog:达 blog:摩 blog:院
    命中:2
    内容:Document<<stored<ID:1510579934220> stored,indexed,tokenized<blog:10月11日杭州云栖大会上,马云表达了对新建成的阿里巴巴全球研究院—阿里巴巴达摩院的愿景,希望达摩院二十年内成为世界第一大经济体,服务世界二十亿人,创造一亿个工作岗位。>>
    内容:Document<stored<ID:1510579934765> stored,indexed,tokenized<blog:达摩院一定也必须要超越英特尔,必须超越微软,必须超越IBM,因为我们生于二十一世纪,我们是有机会后发优势的。>>    
    

    **keyword= :"阿里巴巴达摩院"
    运行结果

    Query = blog:阿 blog:里 blog:巴 blog:巴 blog:达 blog:摩 blog:院
    命中:5
    内容:Document<stored<ID:1510579934220> stored,indexed,tokenized<blog:10月11日杭州云栖大会上,马云表达了对新建成的阿里巴巴全球研究院—阿里巴巴达摩院的愿景,希望达摩院二十年内成为世界第一大经济体,服务世界二十亿人,创造一亿个工作岗位。>>
    内容:Document<stored<ID:1510579934932> stored,indexed,tokenized<blog:阿里巴巴有很多争议,似乎无处不在,我还真想不出有什么东西是我们不做的。互联网是一种思想,是一种技术革命,不应该有界限。跨界乐趣无穷。我觉得阿里巴巴的跨界还不错>>
    内容:Document<stored<ID:1510579934765> stored,indexed,tokenized<blog:达摩院一定也必须要超越英特尔,必须超越微软,必须超越IBM,因为我们生于二十一世纪,我们是有机会后发优势的。>>
    内容:Document<stored<ID:1510579934474> stored,indexed,tokenized<blog:中国互联网界,阿里巴巴被认为是技术实力最弱的公司。我确实不懂技术,承认不懂技术不丢人,不懂装懂才丢人。>>
    内容:Document<stored<ID:1510579934606> stored,indexed,tokenized<blog:阿里巴巴未来二十年的目标是打造世界第五大经济体,不是我们狂妄,而是世界需要这么一个经济体,也一定会有这么一个经济体。>>
    

    第四步:更新索引文档

    import org.apache.lucene.analysis.Analyzer;
    import org.apache.lucene.analysis.standard.StandardAnalyzer;
    import org.apache.lucene.document.*;
    import org.apache.lucene.index.*;
    import org.apache.lucene.store.Directory;
    import org.apache.lucene.store.LockObtainFailedException;
    import org.apache.lucene.store.SimpleFSDirectory;
    import org.apache.lucene.util.Version;
    
    public class LuceneUpdateDemo {
        public static void main(String[] args) {
            // 实例化IKAnalyzer分词器
            Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_47);
    
            Directory directory = null;
            IndexWriter iwriter;
            try {
                // 索引目录
                directory = new SimpleFSDirectory(new File("D://test/lucene_index"));
    
                // 配置IndexWriterConfig
                IndexWriterConfig iwConfig = new IndexWriterConfig(Version.LUCENE_47, analyzer);
                iwConfig.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
                iwriter = new IndexWriter(directory, iwConfig);
                // 写入索引
                Document doc = new Document();
                String id = "1510579934220";
                doc.add(new StringField("ID", id, Field.Store.YES));
                doc.add(new TextField("blog", "更新文档后->达摩院一定也必须要超越英特尔,必须超越微软,必须超越IBM,因为我们生于二十一世纪,我们是有机会后发优势的。", Field.Store.YES));
                //先根据Term ID 删除,在建立新的索引
                iwriter.updateDocument(new Term("ID", id), doc);
                iwriter.close();
                System.out.println("更新索引成功:" + 1511233039462L);
            } catch (CorruptIndexException e) {
                e.printStackTrace();
            } catch (LockObtainFailedException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (directory != null) {
                    try {
                        directory.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

    在执行第三步查询,即可查看更新结果

    第五步:索引删除

    package top.yuyufeng.learn.lucene.demo1;
    
    import org.apache.lucene.analysis.Analyzer;
    import org.apache.lucene.analysis.standard.StandardAnalyzer;
    import org.apache.lucene.index.*;
    import org.apache.lucene.search.IndexSearcher;
    import org.apache.lucene.store.Directory;
    import org.apache.lucene.store.SimpleFSDirectory;
    import org.apache.lucene.util.Version;
    
    import java.io.File;
    import java.io.IOException;
    
    /**
     * @author yuyufeng
     * @date 2017/11/21
     */
    public class LuceneDeleteDemo {
        public static void main(String[] args) {
            // Lucene Document的域名
            String fieldName = "blog";
            Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_47);
            Directory directory = null;
            IndexReader ireader = null;
            IndexSearcher isearcher;
            IndexWriter iwriter = null;
            try {
                //索引目录
                directory = new SimpleFSDirectory(new File("D://test/lucene_index"));
                // 配置IndexWriterConfig
                IndexWriterConfig iwConfig = new IndexWriterConfig(Version.LUCENE_47, analyzer);
                iwConfig.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
                ireader = DirectoryReader.open(directory);
                iwriter = new IndexWriter(directory, iwConfig);
                iwriter.deleteDocuments(new Term("ID","1511235710648"));
                //使用IndexWriter进行Document删除操作时,文档并不会立即被删除,而是把这个删除动作缓存起来,当IndexWriter.Commit()或IndexWriter.Close()时,删除操作才会被真正执行。
                iwriter.commit();
                iwriter.close();
                ireader.close();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (directory != null) {
                    try {
                        directory.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
    方法 说明
    DeleteDocuments(Query query) 根据Query条件来删除单个或多个Document
    DeleteDocuments(Query[] queries) 根据Query条件来删除单个或多个Document
    DeleteDocuments(Term term) 根据Term来删除单个或多个Document
    DeleteDocuments(Term[] terms) 根据Term来删除单个或多个Document
    DeleteAll() 删除所有的Document

    相关文章

      网友评论

        本文标题:搜索学习入门--Lucene初体验(Lucene索引的增删改查)

        本文链接:https://www.haomeiwen.com/subject/cpuosftx.html