zoukankan      html  css  js  c++  java
  • Lucene的基本概念----转载yufenfei的文章

    Lucene的基本概念

    Lucene是什么?

        Lucene是一款高性能、可扩展的信息检索工具库。信息检索是指文档搜索、文档内信息搜索或者文档相关的元数据搜索等操作。

    信息检索流程如下:

          1、 将即将检索的资源集合放到本地,并使用某种特定的结构存储,称为索引,这个索引的集合称为索引库。由于索引库的结构按照专门为快速查询设计的,所以查询的速度非常的快;

          2、 搜索操作时都是在本地的索引库中进行查找;

    所以对于全文检索功能的开发,要做两方面:索引库管理(维护索引库中的数据)、在索引库中进行搜索。而Lucene就是操作索引库的工具;

    索引库是什么样子?

          索引库是一个目录,里面是一些二级制文件,就如同数据库,所有的数据也是以文件的形式存放在文件系统中的。我们不能直接操作这些二级制文件,而是使用Lucene提供的API完成相应的操作,就像数据库使用SQL语句一样。

    对索引库的操作可以分为两种:管理与查询。

       1、 管理索引库使用的IndexWriter;

       2、从索引库中查询使用IndexSearcher。

    Lucene的数据结构为 Document与Field。

    Document代表是一条数据,Field代表数据中的一个属性。一个Document中有多个Field,Field的值为String型,因为Lucene只处理文本;

    我们只需要把我们的程序中的对象转换为Doucemnt,就可以交给Lucene管理了,搜索的结果中的数据列表也是Document的集合;

    OK,我们来做一个实例,还原一下整个流程

    1、创建一个用户类,用于实例化用户数据

    Java代码  
    1. public class User {  
    2.   
    3.     private Long id;  
    4.     private String name;  
    5.     private int age;  
    6.     private String sex;  
    7.     private Date birthday;  
    8.     public User(Long id, String name, int age, String sex, Date birthday) {  
    9.         super();  
    10.         this.id = id;  
    11.         this.name = name;  
    12.         this.age = age;  
    13.         this.sex = sex;  
    14.         this.birthday = birthday;  
    15.     }  
    16.    //get/set方法,这里省略  
    17. }  
    public class User {
    
    	private Long id;
    	private String name;
    	private int age;
    	private String sex;
    	private Date birthday;
    	public User(Long id, String name, int age, String sex, Date birthday) {
    		super();
    		this.id = id;
    		this.name = name;
    		this.age = age;
    		this.sex = sex;
    		this.birthday = birthday;
    	}
       //get/set方法,这里省略
    }

    2、生成即将检索的资源数据

    Java代码  
    1. public class DataUtil {  
    2.     /** 
    3.      * 检索资源数据的准备; 
    4.      *   这里的数据可以来源数据库、文件系统等 
    5.      * @return 
    6.      */  
    7.     public static List<User> getUsers(){  
    8.         List<User> list =new ArrayList<User>();  
    9.         User user =new User(1L,"张三1",20,"man",new Date());  
    10.         list.add(user);  
    11.         user =new User(2L,"张三2",20,"man",new Date());  
    12.         list.add(user);  
    13.         user =new User(3L,"张三3",20,"woman",new Date());  
    14.         list.add(user);  
    15.         user =new User(4L,"张三4",20,"man",new Date());  
    16.         list.add(user);  
    17.         user =new User(5L,"张三5",20,"man",new Date());  
    18.         list.add(user);  
    19.         user =new User(6L,"张三6",20,"woman",new Date());  
    20.         list.add(user);  
    21.         return list;  
    22.     }  
    23. }  
    public class DataUtil {
    	/**
    	 * 检索资源数据的准备;
    	 *   这里的数据可以来源数据库、文件系统等
    	 * @return
    	 */
    	public static List<User> getUsers(){
    		List<User> list =new ArrayList<User>();
    		User user =new User(1L,"张三1",20,"man",new Date());
    		list.add(user);
    		user =new User(2L,"张三2",20,"man",new Date());
    		list.add(user);
    		user =new User(3L,"张三3",20,"woman",new Date());
    		list.add(user);
    		user =new User(4L,"张三4",20,"man",new Date());
    		list.add(user);
    		user =new User(5L,"张三5",20,"man",new Date());
    		list.add(user);
    		user =new User(6L,"张三6",20,"woman",new Date());
    		list.add(user);
    		return list;
    	}
    }

    3、Lucene创建索引库及查询

    Java代码  
    1. public class IndexWriterDemo {  
    2.     /** 
    3.      * 将即将检索的资源写入索引库 
    4.      * @param writer 
    5.      * @throws Exception 
    6.      */  
    7.     public void buildDocs(IndexWriter writer)throws Exception {  
    8.         writer.deleteAll();//清空索引库里已存在的文档(document)  
    9.         List<User> list = DataUtil.getUsers();//得到数据资源  
    10.         System.out.println("buildDocs()->总人数为 :"+list.size());  
    11.         for(User user :list){  
    12.             Document doc = new Document();//创建索引库的文档  
    13.             doc.add(new Field("id",String.valueOf(user.getId()),Store.YES,Index.NO));  
    14.             doc.add(new Field("name",user.getName(),Store.YES,Index.ANALYZED));  
    15.             doc.add(new Field("age",String.valueOf(user.getAge()),Store.YES,Index.ANALYZED));  
    16.             doc.add(new Field("sex",user.getSex(),Store.YES,Index.ANALYZED));  
    17.             doc.add(new Field("birthday",String.valueOf(user.getBirthday()),Store.YES,Index.ANALYZED));  
    18.             writer.addDocument(doc);//将文档写入索引库  
    19.         }  
    20.         int count =writer.numDocs();  
    21.         writer.forceMerge(100);//合并索引库文件  
    22.         writer.close();  
    23.         System.out.println("buildDocs()->存入索引库的数量:"+count);  
    24.     }  
    25.   
    26.     /** 
    27.      * 从索引库中搜索你要查询的数据 
    28.      * @param searcher 
    29.      * @throws IOException 
    30.      */  
    31.     public void searcherDocs(IndexSearcher searcher) throws IOException{  
    32.         Term term =new Term("sex", "man");//查询条件,意思是我要查找性别为“man”的人  
    33.         TermQuery query =new TermQuery(term);  
    34.         TopDocs docs =searcher.search(query, 100);//查找  
    35.         System.out.println("searcherDoc()->男生人数:"+docs.totalHits);  
    36.         for(ScoreDoc doc:docs.scoreDocs){//获取查找的文档的属性数据  
    37.             int docID=doc.doc;  
    38.             Document document =searcher.doc(docID);  
    39.             String str="ID:"+document.get("id")+",姓名:"+document.get("name")+",性别:"+document.get("sex");  
    40.             System.out.println("人员信息:"+str);  
    41.         }  
    42.     }  
    43.   }  
    public class IndexWriterDemo {
    	/**
    	 * 将即将检索的资源写入索引库
    	 * @param writer
    	 * @throws Exception
    	 */
    	public void buildDocs(IndexWriter writer)throws Exception {
    		writer.deleteAll();//清空索引库里已存在的文档(document)
    		List<User> list = DataUtil.getUsers();//得到数据资源
    		System.out.println("buildDocs()->总人数为 :"+list.size());
    		for(User user :list){
    			Document doc = new Document();//创建索引库的文档
    			doc.add(new Field("id",String.valueOf(user.getId()),Store.YES,Index.NO));
    			doc.add(new Field("name",user.getName(),Store.YES,Index.ANALYZED));
    			doc.add(new Field("age",String.valueOf(user.getAge()),Store.YES,Index.ANALYZED));
    			doc.add(new Field("sex",user.getSex(),Store.YES,Index.ANALYZED));
    			doc.add(new Field("birthday",String.valueOf(user.getBirthday()),Store.YES,Index.ANALYZED));
    			writer.addDocument(doc);//将文档写入索引库
    		}
    		int count =writer.numDocs();
    		writer.forceMerge(100);//合并索引库文件
    		writer.close();
    		System.out.println("buildDocs()->存入索引库的数量:"+count);
    	}
    
    	/**
    	 * 从索引库中搜索你要查询的数据
    	 * @param searcher
    	 * @throws IOException
    	 */
    	public void searcherDocs(IndexSearcher searcher) throws IOException{
    		Term term =new Term("sex", "man");//查询条件,意思是我要查找性别为“man”的人
    		TermQuery query =new TermQuery(term);
    		TopDocs docs =searcher.search(query, 100);//查找
    		System.out.println("searcherDoc()->男生人数:"+docs.totalHits);
    		for(ScoreDoc doc:docs.scoreDocs){//获取查找的文档的属性数据
    			int docID=doc.doc;
    			Document document =searcher.doc(docID);
    			String str="ID:"+document.get("id")+",姓名:"+document.get("name")+",性别:"+document.get("sex");
    			System.out.println("人员信息:"+str);
    		}
    	}
      }
    

    4、测试

    Java代码  
    1. public class TestIndexWriterRAMDirectory {  
    2.     private IndexWriter writer=null;  
    3.     private Directory directory=null;  
    4.     private IndexReader reader = null;  
    5.     private IndexSearcher searcher=null;  
    6.     private IndexWriterDemo demo =new IndexWriterDemo();  
    7.       
    8.     @Before  
    9.     public void setUp() throws Exception {  
    10.         directory = new RAMDirectory();  
    11.         IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_36,new SimpleAnalyzer(Version.LUCENE_36));  
    12.         writer = new IndexWriter(directory,config);  
    13.     }  
    14.   
    15.     @Test  
    16.     public void testAddDoc()throws Exception {  
    17.         /**生成索引库*/  
    18.         demo.buildDocs(writer);  
    19.           
    20.         /**查询数据*/  
    21.         reader = IndexReader.open(directory);  
    22.         searcher =new IndexSearcher(reader);  
    23.         demo.searcherDocs(searcher);  
    24.     }  
    25. }  
    public class TestIndexWriterRAMDirectory {
    	private IndexWriter writer=null;
    	private Directory directory=null;
    	private IndexReader reader = null;
    	private IndexSearcher searcher=null;
    	private IndexWriterDemo demo =new IndexWriterDemo();
    	
    	@Before
    	public void setUp() throws Exception {
    		directory = new RAMDirectory();
    		IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_36,new SimpleAnalyzer(Version.LUCENE_36));
    		writer = new IndexWriter(directory,config);
    	}
    
    	@Test
    	public void testAddDoc()throws Exception {
    		/**生成索引库*/
    		demo.buildDocs(writer);
    		
    		/**查询数据*/
    		reader = IndexReader.open(directory);
    		searcher =new IndexSearcher(reader);
    		demo.searcherDocs(searcher);
    	}
    }
    

    测试结果

    Java代码  
    1. buildDocs()->总人数为 :6  
    2. buildDocs()->存入索引库的数量:6  
    3. searcherDoc()->男生人数:4  
    4. 人员信息:ID:1,姓名:张三1,性别:man  
    5. 人员信息:ID:2,姓名:张三2,性别:man  
    6. 人员信息:ID:4,姓名:张三4,性别:man  
    7. 人员信息:ID:5,姓名:张三5,性别:man  
    buildDocs()->总人数为 :6
    buildDocs()->存入索引库的数量:6
    searcherDoc()->男生人数:4
    人员信息:ID:1,姓名:张三1,性别:man
    人员信息:ID:2,姓名:张三2,性别:man
    人员信息:ID:4,姓名:张三4,性别:man
    人员信息:ID:5,姓名:张三5,性别:man
    

    OK,代码完毕

    实例的Lucene版本为:lucene-3.6.1

    在这再次说下Lucene检索的整个流程(请参考demo的代码)

    1、建立索引的执行过程 

         在建立索引时,先要把文档存到索引库中,还要更新词汇表。

    操作步骤如下:

    (1)、把数据对象转换成相应的Document,其中的属性转为Field;

    (2)、调用工具IndexWriter的addDocument(doc),把Document添加到索引库中;

    (3)、Lucene做的操作:

           把文档存到索引库中,并自动指定一个内部编号,用来唯一标识这个条数据;内部编号类似与这条数据的地址,在索引库内部的数据进行调整后,这个编号就可能会改变,同时词汇表中的引用的编号也会做相应的改变,以保 证正确。

          更新词汇表。把文本中的词找出来放到词汇表中,简历与文档的对应关系。要把那些词放到词汇表中呢?这就用到一个叫Analyzer(分词器)的工具。他的作用是把一段文本中的词按照规则取出所包含的所有词。对应的是Analyzer类,这是一个抽象类,切分词的具体规则是由其子类实现。

    在把对象的属性转化为 Field时,相关代码为:

       doc.add(new Field(“title”,article.getTitle(), Store.YES, Index.Analyzed))

    其中第三个参数的意思为

    Store.NO 不存储属性的值;

    Store.YES 存储属性的值

    第四个参数

    Index.NO 不建立索引

    Index.ANALYZED 分词后建立索引

    Index.NOT_ANALYZED 不分词,把整个内容作为一个词建立索引

    Store是影响搜索出的结构是否有指定属性的原始内容。

    Index是影响是否可以从这个属性中查询,或者是查询时可以查其中的某些词,还是要把整个内容作为一个词进行查询。

    2、从索引库中搜索的执行过程(QueryParse、TopDocs、ScoreDoc)

    在进行搜索时,先在词汇表中查找,得到符合条件的文档编号列表。再根据文档编号真正的取数据(Document)

    操作步骤如下:

    (1)、把要查询字符串转为Query对象。这就像在Hiberante总是用HQL查询时,也要先调用Session.createQuery(hql)转成Hibernate的Query对象一样。把查询字符串转换成Query是使用QueryParser,或者使用MultiFieldQueryParser。查询字符串也要先经过Analyzer(分词器)。要求检索时使用Analyzer要与监理索引使用的Analzyer要一致,否则可能搜索不出正确的结果。

    (2)、调用IndexSearcher.search(),进行查询,得到结果。此方法返回未TopDocs,是包含结果的多个信息的一个对象。其中有totalHits代表记录数,ScoreDoc的数组。ScoreDoc是代表一个结果的相关度得分与文档编号等信息的对象。

    (3)、取出要用到的数据列表。调用IndexSearcher.doc(scoreDoc.doc)以取出指定编号对应的Document数据,在分页时要用到:一次只取一页的数据。

    lucene.rar

  • 相关阅读:
    (三)对极几何
    Pythonista中文教程
    Pythonista中文文档
    资源:《C语言程序设计(第五版)谭浩强》及《C语言程序设计:学习辅导(第五版)谭浩强》PDF下载
    重庆邮电大学2020计算机专硕375分经验分享
    LeetCode题目汇总
    CCF-CSP题目汇总
    CCF-CSP:201909-3字符画
    CCF-CSP:201909-2小明种苹果(续)
    CCF-CSP:201909-1小明种苹果
  • 原文地址:https://www.cnblogs.com/tangzeqi/p/8458261.html
Copyright © 2011-2022 走看看