5八、lucene

数据分类:html

一、结构化数据:格式固定,长度固定,数据类型固定,例如:数据库中的数据,java

二、非结构化数据:和上面相反,例如:word文档,pdf文档,邮件,htmlspring

 

数据的查询:数据库

一、结构化数据的查询:apache

SQL语句,特色:简单,速度快windows

二、非结构化数据的查询:数据结构

把非结构化数据变成结构化数据:先根据空格进行字符串的拆分,获得一个单词列表,基于单词列表建立一个索引(一个为了提升查询速度,建立某种数据结构的集合),查询索引,根据单词和文档的对应关系找到文档列表。工具

 

应用场景:搜索引擎

一、搜索引擎编码

二、站内搜索

三、电商搜索

四、只要有搜索的地方

 

lucene:一个基于java开发全文检索的工具包

实现全文检索的流程:

一、建立索引

1·一、得到文档

原始文档:要基于那些数据来进行搜索,那么这些数据就是原始文档

搜索引擎得到文档:使用爬虫得到原始文档

站内搜索得到文档:数据库中的数据

磁盘得到文档:直接使用io流读取磁盘上的文档

1·二、构建文档对象

对应每一个原始文档建立一个Document对象,每一个Document对象中包含多个域,域中保存就是原始文档数据,包含域的名称和值。

注意:每一个文档都有一个惟一的编号,就是文档ID

1·三、分析文档

分词的过程:

    一、根据空格进行字符串拆分,获得一个单词列表

    二、把单词统一转换成小写

    三、去除标点符号

    四、去除停用词(无心义的词)

每一个关键词都封装成一个term对象中,包含关键词所在域和关键词自己。

注意:不一样的域中拆分出来的相同的关键词是不一样的term

1·四、建立索引

基于关键词列表建立一个索引,保存到索引库中。索引库中包含:索引,document对象,关键词和文档的对应关系。

补充:经过词语找文档,这种索引的结构叫倒排索引结构。

 

二、查询索引

2·一、用户查询接口

用户输入查询条件的地方,例如:百度的搜索框

2·二、把关键词封装成一个查询对象,包含:要查询的域和要搜索的关键词

2·三、执行查询,根据要查询的关键词到对应的域上进行搜索

2·四、渲染结果,根据文档的id找到文档对象,对关键词进行处理,最终展现出来

 

入门代码:

一、添加MAVEN依赖

<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>
</dependencies>


 二、代码建立索引

public void createIndex() throws Exception{

        File file = new File("./index");
        if (!file.exists()){
            file.mkdirs();
        }
/*
        Directory directory = new RAMDirectory();//把索引库保存到内存中,不推荐
*/
        //建立一个Director对象,指定索引库保存的位置
        Directory directory = FSDirectory.open(file.toPath());

        //基于Direcotry对象建立一个indexWriter对象
        IndexWriter indexWriter = new IndexWriter(directory,new IndexWriterConfig());
        //读取磁盘上的文件,对应每一个文件建立一个文档对象
        File orgfile = new File("");
        File[] files = orgfile.listFiles();
        for (File f : files){
            //取文件名
            String filename = f.getName();
            //文件的路径
            String filepath = f.getPath();
            //文件的内容
            String fileContent = FileUtils.readFileToString(f, "utf-8");
            //文件的大小
            long filesize = FileUtils.sizeOfDirectory(f);
            //建立field
            //参数1:域的名称,参数2:域的内容,参数3:是否存储
            Field fieldName = new TextField("name",filename,Field.Store.YES);
            Field fieldPath = new TextField("path",filepath,Field.Store.YES);
            Field fieldContent = new TextField("content",fileContent,Field.Store.YES);
            Field fieldsize = new TextField("size",filesize+"",Field.Store.YES);

            //建立文档对象
            Document document = new Document();
            //向文档对象中添加域
            document.add(fieldName);
            document.add(fieldPath);
            document.add(fieldContent);
            document.add(fieldsize);

            //把文档对象写入索引库
            indexWriter.addDocument(document);

        }

        //关闭indexwriter对象
        indexWriter.close();

    }

三、索引库搜索

public void searchIndex()throws Exception{
    //建立一个Director对象,指定索引库的位置
    Directory directory=FSDirectory.open(new File("./index").toPath());
    //建立一个indexReader对象
    IndexReader indexReader = DirectoryReader.open(directory);
    //建立一个IndexSearch对象,构造方法中的参数indexReader对象
    IndexSearcher indexSearcher = new IndexSearcher(indexReader);
    //建立一个Query对象,TermQuery
    Query query = new TermQuery(new Term("content","spring"));
    //执行查询,获得一个TopDocs对象
    //参数1:查询对象,参数2:查询结果返回的最大记录数
    TopDocs topDocs = indexSearcher.search(query, 10);
    //取查询结果的总记录数
    System.out.println(topDocs.totalHits);
    //取文档列表
    ScoreDoc[] scoreDocs = topDocs.scoreDocs;
    for (ScoreDoc doc : scoreDocs){
        int docId = doc.doc;
        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"));
    }

    indexReader.close();

}

步骤:

建立索引库

一、建立一个Director对象,指定索引库保存的位置

二、基于Director对象,建立一个IndexWriter对象

三、读取磁盘文件,对应每一个文件建立一个文档对象

四、向文档对象中添加域

五、把文档对象写入索引库

六、关闭indexwriter对象

public void createIndex() throws Exception{

        File file = new File("./index");
        if (!file.exists()){
            file.mkdirs();
        }
/*
        Directory directory = new RAMDirectory();//把索引库保存到内存中,不推荐
*/
        //建立一个Director对象,指定索引库保存的位置
        Directory directory = FSDirectory.open(file.toPath());

        //基于Direcotry对象建立一个indexWriter对象
        IndexWriter indexWriter = new IndexWriter(directory,new IndexWriterConfig());
        //读取磁盘上的文件,对应每一个文件建立一个文档对象
        File orgfile = new File();
        File[] files = orgfile.listFiles();
        for (File f : files){
            //取文件名
            String filename = f.getName();
            //文件的路径
            String filepath = f.getPath();
            //文件的内容
            String fileContent = FileUtils.readFileToString(f, "utf-8");
            //文件的大小
            long filesize = FileUtils.sizeOfDirectory(f);
            //建立field
            //参数1:域的名称,参数2:域的内容,参数3:是否存储
            Field fieldName = new TextField("name",filename,Field.Store.YES);
            Field fieldPath = new TextField("path",filepath,Field.Store.YES);
            Field fieldContent = new TextField("content",fileContent,Field.Store.YES);
            Field fieldsize = new TextField("size",filesize+"",Field.Store.YES);

            //建立文档对象
            Document document = new Document();
            //向文档对象中添加域
            document.add(fieldName);
            document.add(fieldPath);
            document.add(fieldContent);
            document.add(fieldsize);

            //把文档对象写入索引库
            indexWriter.addDocument(document);

        }

        //关闭indexwriter对象
        indexWriter.close();

    }

 查看索引库:使用luke工具

查询索引库

一、建立一个Director对象,指定索引库的位置

二、建立一个IndexReader对象

三、建立一个IndextSearcher对象,构造方法中的参数IndexReader对象

四、建立一个Query对象,termQuery

五、执行查询,获得一个TopDocs对象

六、取查询结果的总记录数

七、取文档列表

八、打印文档中的内容

九、关闭IndexReader对象

public void searchIndex()throws Exception{
        //建立一个Director对象,指定索引库的位置
        Directory directory=FSDirectory.open(new File("./index").toPath());
        //建立一个indexReader对象
        IndexReader indexReader = DirectoryReader.open(directory);
        //建立一个IndexSearch对象,构造方法中的参数indexReader对象
        IndexSearcher indexSearcher = new IndexSearcher(indexReader);
        //建立一个Query对象,TermQuery
        Query query = new TermQuery(new Term("content","spring"));
        //执行查询,获得一个TopDocs对象
        //参数1:查询对象,参数2:查询结果返回的最大记录数
        TopDocs topDocs = indexSearcher.search(query, 10);
        //取查询结果的总记录数
        System.out.println(topDocs.totalHits);
        //取文档列表
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;
        for (ScoreDoc doc : scoreDocs){
            int docId = doc.doc;
            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"));
        } 
        
        indexReader.close();
        
        
    }
}

 

分析器:

默认使用的是标准分析器StandardAnalyzer

查看分析器的分析效果:

一、建立一个Analyzer对象,StandardAnayzer对象

二、使用分析器对象的tokenStream方法得到宇哥tokenStream对象

三、向tokenStream对象设置一个引用,至关因而一个指针

四、调用tokenStream对象的rest方法,若是不调用抛异常

五、使用while循环遍历tokenStream对象

六、关闭tokenStream对象

public void testTokenStream() throws Exception{
    Analyzer analyzer = new StandardAnalyzer();
    TokenStream tokenStream = analyzer.tokenStream("","wo shi yi ge zifuchuang");
    CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);
    tokenStream.reset();
    while (tokenStream.incrementToken()){
        System.out.println(charTermAttribute.toString());
    }
    tokenStream.close();
}

 

中文分析器:IKAnalyzer

一、添加IKAnalyzer的jar包

二、把配置文件和扩展词典添加到工程的classpath下

注意:扩展词典严禁使用windows记事本编辑保证扩展词典的编码格式是utf-8

扩展词典做用:添加一些新词

停用词词典:无心义的词或者是敏感词汇

 

索引库维护

常见的field:

Field类

数据类型

Analyzed

是否分词

Indexed

是否索引

Stored

是否存储

说明

StringField(FieldName, FieldValue,Store.YES))

字符串

N

Y

Y或N

这个Field用来构建一个字符串Field,可是不会进行分词,会将整个串存储在索引中,好比(订单号,身份证号等)

是否存储在文档中用Store.YES或Store.NO决定

LongField(FieldName, FieldValue,Store.YES)

Long型 

Y

Y

Y或N

这个Field用来构建一个Long数字型Field,进行分词和索引,好比(价格)

是否存储在文档中用Store.YES或Store.NO决定

StoredField(FieldName, FieldValue) 

重载方法,支持多种类型

N

N

Y

这个Field用来构建不一样类型Field

不分析,不索引,但要Field存储在文档中

TextField(FieldName, FieldValue, Store.NO)

TextField(FieldName, reader)

 

字符串

Y

Y

Y或N

若是是一个Reader, lucene猜想内容比较多,会采用Unstored的策略.

添加文档:

public class IndexManager {
    public void addDoucment() throws  Exception{
        //建立一个IndexWriter对象,须要IKAnalyzer做为分析器
        IndexWriter indexWriter = new IndexWriter(FSDirectory.open(new File("./index").toPath()),
                new IndexWriterConfig(new IKAnalyzer()));
        //建立一个document对象
        Document document = new Document();
        document.add(new TextField("name","新添加的问",Field.Store.YES));
        //把文档写入索引库
        indexWriter.addDocument(document);
        indexWriter.close();
    }
}

 

删除索引库:

public void deleteAllDocument() throws Exception{
    //建立一个IndexWriter对象,须要IKAnalyzer做为分析器
    IndexWriter indexWriter = new IndexWriter(FSDirectory.open(new File("./index").toPath()),
            new IndexWriterConfig(new IKAnalyzer()));
    indexWriter.deleteAll();
    indexWriter.close();
}
public void deleteDocumentByTerm()throws Exception{
        IndexWriter indexWriter = new IndexWriter(FSDirectory.open(new File("./index").toPath()),
                new IndexWriterConfig(new IKAnalyzer()));
        indexWriter.deleteDocuments(new Term("name","内容"));
        indexWriter.close();

}

 

更新索引库:

public void updateDocument()throws Exception{

        IndexWriter indexWriter = new IndexWriter(FSDirectory.open(new File("./index").toPath()),
                new IndexWriterConfig(new IKAnalyzer()));
        Document document = new Document();
        document.add(new TextField("name","更新的内容",Field.Store.YES));
        
        indexWriter.updateDocument(new Term("name","内容"),document);
        indexWriter.close();
   
}

 

索引库的查询:

使用Query的子类查询

public class SearchIndex {
    public void testRangeQuery()throws Exception{
        IndexReader indexReader = DirectoryReader.open(FSDirectory.open(new File("./index").toPath()));
        IndexSearcher indexSearcher = new IndexSearcher(indexReader);
        
        //建立一个query对象
        Query query = LongPoint.newRangeQuery("size", 0l, 10000l);
        TopDocs topDocs = indexSearcher.search(query, 10);
        System.out.println(topDocs.totalHits);
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;
        for (ScoreDoc scoreDoc : scoreDocs){
           int docId =  scoreDoc.doc;
            Document document = indexSearcher.doc(docId);
            System.out.println(document.get("name"));
        }
        indexReader.close();
    }
}

 使用QueryPaser进行查询:能够对要查询的内容先分词,而后基于分词的结果再查询

须要添加jar包lucene-queryoarser

public void testQueryParser()throws Exception{
    //建立一个QueryParser对象
    //参数1:默认搜索域,参数2:分析器对象
    QueryParser queryParser = new QueryParser("name",new IKAnalyzer());
    //使用QueryPaser对象建立一个QUery
    Query query = queryParser.parse("这是一个查询的语句")
    //执行查询
    printResult(query);
}
相关文章
相关标签/搜索