Lucene入门

1.需求

2.创建索引

  2.1实现步骤

  2.2.创建lucene项目

  2.3代码实现

3.查询索引

  3.1实现步骤

  3.2代码实现

4.分析器

  4.1标准分析器的分词效果

  4.2IKAnalyzer分析器的分词效果

5.索引库的维护

  5.1Field域的属性

  5.2索引库的添加、删除、修改

6.Lucene索引库查询

  6.1TermQuery

  6.2数据查询和使用QueryParser查询

项目目录:

1.需求

实现一个文件的搜索功能,通过关键字搜索文件,凡是文件名或文件内容包括关键字的文件都需要找出来。还可以根据中文词语进行查询,并且需要支持多个条件查询。

本案例中的原始内容就是磁盘上的文件,如下图:

2.创建索引

2.1实现步骤

第一步:创建一个java工程,并导入jar包。

第二步:创建一个indexwriter对象。

1)指定索引库的存放位置Directory对象

2)指定一个IndexWriterConfig对象。

第二步:创建document对象。

第三步:创建field对象,将field添加到document对象中。

第四步:使用indexwriter对象将document对象写入索引库,此过程进行索引创建。并将索引和document对象写入索引库。

第五步:关闭IndexWriter对象。

2.2创建lucene项目

 

2.3代码实现

public class LuceneFirst {

    //创建索引
    @Test
    public void createIndex() throws Exception {
        //1.创建一个directory对象,指定索引库保存的位置
        //把索引库保存在内存中(不建议这样做)
        //Directory directory = new RAMDirectory();
        //把索引库保存在在磁盘中,指定路径名
        Directory directory = FSDirectory.open(new File("D:\IDEA\IdeaProjects\lucene\temp\index").toPath());
        //2.基于directory对象创建一个indexwriter对象
        IndexWriter indexWriter = new IndexWriter(directory, new IndexWriterConfig());
        //3.读取磁盘上的文件,对应每个文件创建一个文档对象
        File dir = new File("D:\BaiduNetdiskDownload\lucene\02.参考资料\searchsource");
        File[] files = dir.listFiles();
        for (File f : files) {
            //取文件名
            String filename = f.getName();
            //文件路径名
            String filepath = f.getPath();
            //文件内容
            String filecontent = FileUtils.readFileToString(f, "utf-8");
            //文件大小
            long filesize = FileUtils.sizeOf(f);
            //创建Field
            //参数1:域的名称 ,参数2:域的内容 , 参数3:是否存储
            Field fieldName = new TextField("name", filename, Field.Store.YES);
            //Field fieldPath = new TextField("path",filepath,Field.Store.YES);
            //StoreField仅做存储,其下内容不做分词和索引
            Field fieldPath = new StoredField("path", filepath);
            Field fieldContent = new TextField("content", filecontent, Field.Store.YES);
            //Field fieldSize = new TextField("size", filesize + "", Field.Store.YES);//+""是为了将long类型数据转成字符串
            Field fieldSizeValue = new LongPoint("size",filesize);//LongPoint用作运算,如数据范围查询
            Field fieldSizeStore = new StoredField("size",filesize);
            //创建文档对象
            Document document = new Document();
            //向文档对象中添加域
            document.add(fieldName);
            document.add(fieldPath);
            document.add(fieldContent);
            //document.add(fieldSize);
            document.add(fieldSizeValue);
            document.add(fieldSizeStore);
            //5.把文档对象写入索引库
            indexWriter.addDocument(document);

        }
        //6.关闭索引库
        indexWriter.close();
    }
}

D:\IDEA\IdeaProjects\lucene\temp\index为索引库的路径。

注意:new IndexWriterConfig()里面为空时,默认使用标准分词器 StandardAnalyzer,也可以自定义分析器,如:new IndexWriterConfig(new IKAnalyzer());

创建索引完成后,索引库内出现如下文件:

3.查询索引

3.1实现步骤

第一步:创建一个Directory对象,也就是索引库存放的位置。

第二步:创建一个indexReader对象,需要指定Directory对象。

第三步:创建一个indexsearcher对象,需要指定IndexReader对象

第四步:创建一个TermQuery对象,指定查询的域和查询的关键词。

第五步:执行查询。

第六步:返回查询结果。遍历查询结果并输出。

第七步:关闭IndexReader对象

3.2代码实现

@Test
    public void searchIndex() throws Exception {
        //1.创建一个directory对象,指定索引库的位置
        Directory directory = FSDirectory.open(new File("D:\IDEA\IdeaProjects\lucene\temp\index").toPath());
        //2.创建一个indexReader对象
        IndexReader indexReader = DirectoryReader.open(directory);
        //3.创建一个indexSearcher对象,构造方法中的参数indexReader对象
        IndexSearcher indexSearcher = new IndexSearcher(indexReader);
        //4.创建一个query对象,TermQuery
        //参数1:指定查询的域 参数2:指定要查找的关键词
        //Query query = new TermQuery(new Term("content", "spring"));
        Query query = new TermQuery(new Term("name", "apache")); 
//5.执行查询,得到一个TopDocs对象 //参数1:查询对象 参数2:查询结果返回的最大记录数 TopDocs topDocs = indexSearcher.search(query, 10); //6.取查询结果的总记录数 System.out.println("查询总记录数:" + topDocs.totalHits); //7.取文档列表 ScoreDoc[] scoreDocs = topDocs.scoreDocs; //8.打印文档中的 内容 for (ScoreDoc doc : scoreDocs) { //取文档 int docId = doc.doc; //根据id取文档对象 Document document = indexSearcher.doc(docId); System.out.println(document.get("name")); System.out.println(document.get("path")); System.out.println(document.get("size")); //System.out.println(document.get("content")); System.out.println("------------------寂寞的分割线---------------"); } //9.关闭indexreader对象 indexReader.close(); }

查询结果:

4.分析器

4.1标准分析器的分词效果

    @Test
    public void testTokenStream() throws Exception {
        //1.创建一个analyzer对象,standardAnalyzer对象
        Analyzer analyzer = new StandardAnalyzer();//标准分析器只适用于英文文档的分析
       //2.使用分析器对象的tokenStream方法获得一个tokenStream对象
        TokenStream tokenStream = analyzer.tokenStream("", "The spring framework provides a comprehensive programming and configuration model.");
       //3.向tokenStream对象中设置有一个引用,相当于一个指针
        CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);
        //4.调用tokenStream对象的reset方法,如果不调用抛异常
        tokenStream.reset();
        //5.使用while循环遍历tokenStream对象
        while (tokenStream.incrementToken()) {
            System.out.println(charTermAttribute.toString());
        }
        //6.关闭tokenStream对象
        tokenStream.close();
    }

analyzer.tokenStream("", "The spring framework provides a comprehensive programming and configuration model.");

其中第一个参数添加域名,这里我们不添加,第二个参数:标色语句为待分词的内容。

分词效果为:

 4.2IKAnalyzer分析器的分词效果

    @Test
    public void testTokenStream() throws Exception {
        //1.创建一个analyzer对象,standardAnalyzer对象
        //Analyzer analyzer = new StandardAnalyzer();//标准分析器只是用于英文文档的分析
        Analyzer analyzer1 = new IKAnalyzer();//该分析器适用于中文分词
        //2.使用分析器对象的tokenStream方法获得一个tokenStream对象
        //TokenStream tokenStream = analyzer.tokenStream("", "The spring framework provides a comprehensive programming and configuration model.");
        TokenStream tokenStream = analyzer1.tokenStream("","今天奶奶给我买了我最爱吃的喜之郎果冻");
        //3.向tokenStream对象中设置有一个引用,相当于一个指针
        CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);
        //4.调用tokenStream对象的reset方法,如果不调用抛异常
        tokenStream.reset();
        //5.使用while循环遍历tokenStream对象
        while (tokenStream.incrementToken()) {
            System.out.println(charTermAttribute.toString());
        }
        //6.关闭tokenStream对象
        tokenStream.close();
    }

注意: IKAnalyzer分析器适用于无BOM UTF-8 编码文档。也就是说禁止使用windows记事本编辑扩展词典文件。

分词效果:

如果使用标准分析器对中文进行分词,则会变成:

这样是不便于搜索查询的!

5.索引库的维护

5.1Field域的属性

是否分析:是否对域的内容进行分词处理。前提是我们是否要对域的内容进行查询。

是否索引:将Field分析后的词或整个Field值进行索引,只有索引方可搜索到。

比如:商品名称、商品简介分析后进行索引,订单号、身份证号不用分析但也要索引,这些将来都要作为查询条件。

是否存储:将Field值存储在文档中,存储在文档中的Field才可以从Document中获取

比如:商品名称、订单号,凡是将来要从Document中获取的Field都要存储。

是否存储的标准:是否要将内容展示给用户

 5.2索引库的添加、删除、修改

代码实现:

public class IndexManager {

    private IndexWriter indexWriter;

    @Before
    public void init() throws Exception{
        //创建一个indexWriter对象,需要使用使用IkAnalyzer作为分析器
        indexWriter =
                new IndexWriter(FSDirectory.open(new File("D:\IDEA\IdeaProjects\lucene\temp\index").toPath()),
                        new IndexWriterConfig(new IKAnalyzer()));
    }

    //添加索引
    @Test
    public void addDocument() throws Exception{
        //创建一个document对象
        Document document = new Document();
        //向document对象中添加域
        document.add(new TextField("name","新添加的文件", Field.Store.YES));
        document.add(new TextField("content","新添加的文件内容",Field.Store.NO));
        //不需要创建索引的就使用StoreField存储
        document.add(new StoredField("path","D:\IDEA\IdeaProjects\lucene\temp\index"));
        //把文档写入索引库
        indexWriter.addDocument(document);
        //关闭索引库
        indexWriter.close();
    }


=================================================
    
//删除索引 //删除全部索引 @Test public void deleteAllDocument() throws Exception{ //删除全部文档 indexWriter.deleteAll(); //关闭索引库 indexWriter.close(); } //根据查询条件删除索引 @Test public void deleteDocumentByQuery() throws Exception{ indexWriter.deleteDocuments(new Term("name","apache")); indexWriter.close(); } ================================================= //修改索引库,原理就是先删除后添加 @Test public void updateDocument() throws Exception{ //创建一个新的文档对象 Document document = new Document(); //向文档对象中添加域 document.add(new TextField("name","更新后的文档",Field.Store.YES)); document.add(new TextField("name1","更新后的文档1",Field.Store.YES)); document.add(new TextField("name2","更新后的文档2",Field.Store.YES)); //更新操作,先删除再添加 indexWriter.updateDocument(new Term("name","apache"),document); //关闭索引库 indexWriter.close(); } }

6.Lucene索引库查询

对要搜索的信息创建Query查询对象,Lucene会根据Query查询对象生成最终的查询语法,类似关系数据库Sql语法一样Lucene也有自己的查询语法,比如:“name:lucene”表示查询Field的name为“lucene”的文档信息。

         可通过两种方法创建查询对象:

         1)使用Lucene提供Query子类

         2)使用QueryParse解析查询表达式

6.1TermQuery

TermQuery,通过项查询,TermQuery不使用分析器所以建议匹配不分词的Field域查询,比如订单号、分类ID号等。

指定要查询的域和要查询的关键词。

在上文3.2代码实现中有用到TermQuery查询关键词:

 6.2数据范围查询 和 使用QueryParser查询

public class SearchIndex {

    private IndexReader indexReader;
    private IndexSearcher indexSearcher;

    @Before
    public void init() throws Exception{
        indexReader = DirectoryReader.open(FSDirectory.open(new File("D:\IDEA\IdeaProjects\lucene\temp\index").toPath()));
        indexSearcher = new IndexSearcher(indexReader);
    }

    //数据范围查询
    @Test
    public void testRangeQuery() throws Exception{
        //创建一个Query对象,当Field的类为LongPoint时可用于数据范围查询,上文2.3代码实现中就创建了LongPoint类的Field
        Query query = LongPoint.newRangeQuery("size",0,100);
        printResult(query);
    }

    private void printResult(Query query) throws Exception{
        //执行查询
        TopDocs topDocs = indexSearcher.search(query,10);
        System.out.println("总记录数:"+topDocs.totalHits);
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;
        for (ScoreDoc doc:scoreDocs){
            //取文档id
            int docId = doc.doc;
            //根据id取文档对象
            Document document = indexSearcher.doc(docId);
            System.out.println(document.get("name"));
            System.out.println(document.get("path"));
            System.out.println(document.get("size"));
            System.out.println("----------------分割线---------------");
        }
        indexReader.close();
    }

    //使用QueryParser查询    
    @Test
    public void testQueryParser() throws Exception{
        //创建一个queryParser对象,两个参数
        //参数1:设置默认搜索的域  参数2:分析器对象
        QueryParser queryParser = new QueryParser("name",new IKAnalyzer());
        //使用queryParser对象创建一个query对象
        Query query = queryParser.parse("lucene是一个Java开发的全文搜索工具包");
        //执行查询
        printResult(query);
    }
}

使用queryParser时需要注意:

  通过QueryParser也可以创建Query,QueryParser提供一个Parse方法,此方法可以直接根据查询语法来查询。Query对象执行的查询语法可通过System.out.println(query);查询。

需要使用到分析器。建议创建索引时使用的分析器和查询索引时使用的分析器要一致。

原文地址:https://www.cnblogs.com/churujianghudezai/p/12696588.html