zoukankan      html  css  js  c++  java
  • Lucene 搜索的初步探究

    搜索应用程序和 Lucene 之间的关系

    一般的搜索引擎都会采用这样的

    Lucene 采用的是一种称为反向索引(inverted index)的机制。反向索引就是说我们维护了一个词 / 短语表,对于这个表中的每个词 / 短语,都有一个链表描述了有哪些文档包含了这个词 / 短语。这样在用户输入查询条件的时候,就能非常快的得到搜索结果。
    反向索引

    Lucene 软件包的介绍

    org.apache.lucene.document 
    封装要索引的文档所需要的类,比如 Document, Field。 文档一document对象在程序程序中运行
    
    org.apache.lucene.analysis
    对文档进行分词,因为文档在建立索引之前必须要进行分词
    
    
    org.apache.lucene.index
    创建索引以及对创建好的索引进行更新
    IndexWriter 是用来创建索引并添加文档到索引中的,IndexReader 是用来删除索引中的文档的
    
    org.apache.lucene.search
    建立好的索引上进行搜索所需要的类
    IndexSearcher 和 Hits, IndexSearcher 定义了在指定的索引上进行搜索的方法,Hits 用来保存搜索得到的结果。
    

    Lucene建立索引和搜索的几个流程

    建立索引

    1 document 指文档可以死HTML,文本等。并且document是由多个Field对象组成的,可以把一个 Document 对象想象成数据库中的一个记录,而每个 Field 对象就是记录的一个字段。

    2 Field Field 对象是用来描述一个文档的某个属性的,比如一封电子邮件的标题和内容可以用两个 Field 对象分别描述。

    3 Analyzer 对文档进行分词

    4 IndexWriter IndexWriter 是 Lucene 用来创建索引的一个核心的类,他的作用是把一个个的 Document 对象加到索引中来。

    5 Directory 代表了Lucene 的索引的存储的位置 , 有两个实现,第一个是 FSDirectory, 存储在文件系统中的索引 。 RAMDirectory, 存储在内存当中的索引。

    搜索文档

    之前建立好的索引文档,现在我们可以进行对文档进行搜索
    1 Query 是抽象类,有多个继承实现 TermQuery, BooleanQuery, PrefixQuery. 。这些类可以将用户输入的字符串封装成Lucene能够识别的Query

    2 Term Term 是搜索的基本单位 基本的语法是

    Term term = new Term(“fieldName”,”queryWord”);
    

    fieldName 是指要在文档的那个field上查找,queryWord表示要查询的关键词

    3 TermQuery TermQuery是抽象的query的一个之类,

    	TermQuery termQuery = new TermQuery(new Term(“fieldName”,”queryWord”)); 它的构造函数只接受一个参数,那就是一个 Term 对象。
    

    4 IndexSearcher 在建立好的索引上进行搜索,

    5 Hits Hits 是用来保存搜索的结果的。

    建立索引的过程和代码

    	package LuceneTest.LuceneTest;
    
    import java.io.File;
    import java.io.FileReader;
    import java.nio.file.Paths;
    
    import org.apache.lucene.analysis.Analyzer;
    import org.apache.lucene.analysis.standard.StandardAnalyzer;
    import org.apache.lucene.document.Document;
    import org.apache.lucene.document.Field.Store;
    import org.apache.lucene.document.TextField;
    import org.apache.lucene.index.IndexWriter;
    import org.apache.lucene.index.IndexWriterConfig;
    import org.apache.lucene.store.Directory;
    import org.apache.lucene.store.FSDirectory;
    
    /**
     * 建立索引的类
     * @author Ni Shengwu
     *
     */
    public class Indexer {
    
    private IndexWriter writer; //写索引实例
    
        //构造方法,实例化IndexWriter
        public Indexer(String indexDir) throws Exception {
            Directory dir = FSDirectory.open(Paths.get(indexDir));
            Analyzer analyzer = new StandardAnalyzer(); //标准分词器,会自动去掉空格啊,is a the等单词
            IndexWriterConfig config = new IndexWriterConfig(analyzer); //将标准分词器配到写索引的配置中
            writer = new IndexWriter(dir, config); //实例化写索引对象
        }
    
        //关闭写索引
        public void close() throws Exception {
            writer.close();
        }
    
        //索引指定目录下的所有文件
        public int indexAll(String dataDir) throws Exception {
            File[] files = new File(dataDir).listFiles(); //获取该路径下的所有文件
            for(File file : files) {
                indexFile(file); //调用下面的indexFile方法,对每个文件进行索引
            }
            return writer.numDocs(); //返回索引的文件数
        }
    
        //索引指定的文件
        private void indexFile(File file) throws Exception {
            System.out.println("索引文件的路径:" + file.getCanonicalPath());
            Document doc = getDocument(file); //获取该文件的document
            writer.addDocument(doc); //调用下面的getDocument方法,将doc添加到索引中
        }
    
        //获取文档,文档里再设置每个字段,就类似于数据库中的一行记录
        private Document getDocument(File file) throws Exception{
            Document doc = new Document();
            //添加字段
            doc.add(new TextField("contents", new FileReader(file))); //添加内容
            doc.add(new TextField("fileName", file.getName(), Store.YES)); //添加文件名,并把这个字段存到索引文件里
            doc.add(new TextField("fullPath", file.getCanonicalPath(), Store.YES)); //添加文件路径
            return doc;
        }
    
        public static void main(String[] args) {
            String indexDir = "D:\lucene\index"; //将索引保存到的路径
            String dataDir = "D:\lucene\data"; //需要索引的文件数据存放的目录
            Indexer indexer = null;
            int indexedNum = 0;
            long startTime = System.currentTimeMillis(); //记录索引开始时间
            try {
                indexer = new Indexer(indexDir);
                indexedNum = indexer.indexAll(dataDir);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    indexer.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            long endTime = System.currentTimeMillis(); //记录索引结束时间
            System.out.println("索引耗时" + (endTime-startTime) + "毫秒");
            System.out.println("共索引了" + indexedNum + "个文件");
        }
     }
    

    建立一个搜索的过程

    	package LuceneTest.LuceneTest;
    
    import java.nio.file.Paths;
    
    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.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.FSDirectory;
    
    public class Searcher {
    
    public static void search(String indexDir, String q) throws Exception {
    
        Directory dir = FSDirectory.open(Paths.get(indexDir)); //获取要查询的路径,也就是索引所在的位置
        IndexReader reader = DirectoryReader.open(dir);
        IndexSearcher searcher = new IndexSearcher(reader);
        Analyzer analyzer = new StandardAnalyzer(); //标准分词器,会自动去掉空格啊,is a the等单词
        QueryParser parser = new QueryParser("contents", analyzer); //查询解析器
        Query query = parser.parse(q); //通过解析要查询的String,获取查询对象
    
        long startTime = System.currentTimeMillis(); //记录索引开始时间
        TopDocs docs = searcher.search(query, 10);//开始查询,查询前10条数据,将记录保存在docs中
        long endTime = System.currentTimeMillis(); //记录索引结束时间
        System.out.println("匹配" + q + "共耗时" + (endTime-startTime) + "毫秒");
        System.out.println("查询到" + docs.totalHits + "条记录");
    
        for(ScoreDoc scoreDoc : docs.scoreDocs) { //取出每条查询结果
            Document doc = searcher.doc(scoreDoc.doc); //scoreDoc.doc相当于docID,根据这个docID来获取文档
            System.out.println(doc.get("fullPath")); //fullPath是刚刚建立索引的时候我们定义的一个字段
        }
        reader.close();
    }
    
    public static void main(String[] args) {
        String indexDir = "D:\lucene\index";
        String q = "import"; //查询这个字符串
        try {
            search(indexDir, q);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    }
  • 相关阅读:
    jquery 学习(五)
    iOS: 学习笔记, Swift名字空间
    iOS: 学习笔记, Swift与C指针交互(译)
    iOS: 学习笔记, Swift运算符定义
    iOS: 学习笔记, Swift与Objective-C混用总结
    iOS: 学习笔记, Swift与Objective-C混用简明教程(转载)
    股票查询接口: 腾讯
    iOS: 学习笔记, swift扩展
    iOS:Swift界面实例1, 简单界面
    iOS: 学习笔记, 用代码驱动自动布局实例(swift)
  • 原文地址:https://www.cnblogs.com/wangshouchang/p/6869523.html
Copyright © 2011-2022 走看看