Lucene5学习之增量索引(Zoie)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介:

      清明节放假期间,就一直在思考着Lucene增量索引问题,通过google我了解到了Zoie的存在,于是就开始2天的学习Zoie之旅,对Zoie的原理以及使用基本掌握,还特地使用Zoie实现了Lucene索引增量索引。不过Zoie已经好久没更新了,Zoie目前版本只支持到Lucene4.3.0,为此我花了2个多小时,修改了Zoie的源码将它升级使其支持Lucene5.0,我修改过的Zoie最新源码我已经上传到我的百度网盘,下载地址如下:

    Zoie-for-Lucene5.0源码

    Zoie-for-Lucene4.3源码

    Zoie-5.0.0-各模块打包好的jar包

如果你使用Maven的话,那依赖的Zoie相关jar你需要手动install到你本地的仓库里,特此提醒。Zoie5.0相关jar包上面提供的3个下载地址中最后一个是我打包好的jar,你引入一个zoie-core即可。

 

 

    先来说说Zoie的增量索引原理吧,摘自Zoie的官方Wiki:

利用两个内存索引一个硬盘索引实现实时搜索的原理

(1) 当系统启动的时候,索引处在Sleeping状态,这时Mem结构中,只有索引A,索引B为null,索引A为_currentWritable,_currentReadOnly为null,_diskIndexReader为硬盘索引的IndexReader。由于内存中索引的IndexReader是每添加完文档后立刻更新的,而且速度很快,而硬盘上的索引一旦打开,在下次合并之前,一直使用,可以保证新添加的文档能够马上被搜索到。

 (2) 当A中的文档数量达到一定的数量的时候,需要同硬盘上的索引进行合并,因此要进入Working状态。合并是一个相对比较长的过程,这时候会创建内存索引B,在合并过程中新添加的文档全部索引到B中。此时的Mem结构中,有内存索引A,内存索引B,索引A为currentReadOnly,索引B为currentWritable,diskIndexReader为硬盘索引的IndexReader。此时要获得ZoieSystem的IndexReader,则三个IndexReader全都返回,由于索引B的IndexReader是添加文档后立刻更新的,因而能够保证新添加的文档能够马上被搜索到,这个时候虽然索引A已经在同硬盘索引进行合并,然而由于硬盘索引的IndexReader还没有重新打开,因而索引A中的数据不会被重复搜到。

 (3) 当索引A中的数据已经完全合并到硬盘上之后,则要重新打开硬盘索引的IndexReader,打开完毕后,创建一个新的Mem结构,原来的索引B作为索引A,为currentWritable,原来的索引A被抛弃,设为null,currentReadOnly也设为null,diskIndexReader为新打开的硬盘索引的IndexReader。然后通过无缝切换用新的Mem结构替代旧的Mem结构,然后索引进入Sleeping状态。

上面的文字说的不够通俗易懂,我用更直白的话再解释一下:Zoie的增量索引原理是这样的,首先你可能会有一个定时器去不断检索是否有新增数据,发现了新数据,那首先会把新增的数据索引到内存目录A(RAMDirectory-A)中,当总不能一直让内存目录A中写索引啊,毕竟你占用的是内存,所以为内存目录A设定一个阀值,超过这个限定阀值就触发内存目录A中索引flush到硬盘索引目录C中,当内存目录A中索引还没有完全写入到硬盘索引目录C中且硬盘索引目录C的IndexReader还没有重新open的话,你通过IndexSearcher是查询不到的,这时就设计了一个内存索引目录B,即在内存索引目录A在往硬盘索引目录C中写索引的同时,也往内存索引目录B中写做个备份,这时使用Lucene中的MultiReader把B和C作为一个索引目录进行查询,之所以不包括A是因为A还没写完,前面博客我已经将过了Lucene的多目录搜索,你应该懂的,所以你新增数据之所以能几乎近实时的被你搜索到,是因为写入到了一个备份的索引目录B中,然后联合硬盘索引目录C(因为硬盘索引目录C在内存索引目录A里的索引合并到C过程还没完成之前,新增的索引在C中是搜索不到),当A和C的合并过程完成后,硬盘索引目录C的IndexReasder重新打开,保证新增的索引能被IndexSearcher搜索到,同时把B作为A,废弃A,再进入下一个循环.......
     核心就是利用两个内存目录,一个内存目录用来联合硬盘索引目录进行多目录查询,另一个目录只管进行索引合并到硬盘索引目录操作即可。

 

    放假花了2天使用Zoie写了一个增量索引的Demo,示例程序就是模拟数据库表数据动态插入新数据后,能立马被准实时被索引到,且被搜索到。下面就直接上代码了:

    

Java代码   收藏代码
  1. package com.yida.framework.lucene5.incrementindex;  
  2.   
  3. import java.io.File;  
  4. import java.util.ArrayList;  
  5. import java.util.List;  
  6.   
  7. import org.ansj.lucene5.AnsjAnalyzer;  
  8. import org.apache.lucene.analysis.Analyzer;  
  9. import org.apache.lucene.search.similarities.DefaultSimilarity;  
  10.   
  11. import proj.zoie.api.DataConsumer.DataEvent;  
  12. import proj.zoie.api.ZoieException;  
  13. import proj.zoie.api.indexing.ZoieIndexableInterpreter;  
  14. import proj.zoie.impl.indexing.DefaultIndexReaderDecorator;  
  15. import proj.zoie.impl.indexing.ZoieConfig;  
  16. import proj.zoie.impl.indexing.ZoieSystem;  
  17.   
  18. /** 
  19.  * Zoie增量索引测试 
  20.  * @author Lanxiaowei 
  21.  * 
  22.  */  
  23. @SuppressWarnings({"unchecked","rawtypes"})  
  24. public class ZoieIndex {  
  25.       
  26.     /**最大增量索引数量*/  
  27.     public static final long MAX_INCREMENT_INDEX_NUMBER = Long.MAX_VALUE;  
  28.     /**索引目录*/  
  29.     public String userIndexPath;  
  30.       
  31.     public ZoieSystem zoieSystem;  
  32.       
  33.     /**队列中放入多少项才触发索引*/  
  34.     private  int zoieBatchSize;  
  35.       
  36.     /**等待多长时间才触发索引*/  
  37.     private int zoieBatchDelay;  
  38.       
  39.     /**分词器*/  
  40.     private Analyzer analyzer;  
  41.       
  42.     private PersonDao personDao;  
  43.       
  44.     public ZoieIndex(String userIndexPath, Analyzer analyzer,  
  45.             PersonDao personDao) {  
  46.         super();  
  47.         this.userIndexPath = userIndexPath;  
  48.         this.analyzer = analyzer;  
  49.         this.personDao = personDao;  
  50.     }  
  51.   
  52.     public ZoieIndex(String userIndexPath, Analyzer analyzer,  
  53.             PersonDao personDao, int zoieBatchSize, int zoieBatchDelay) {  
  54.         super();  
  55.         this.userIndexPath = userIndexPath;  
  56.         this.analyzer = analyzer;  
  57.         this.personDao = personDao;  
  58.         this.zoieBatchSize = zoieBatchSize;  
  59.         this.zoieBatchDelay = zoieBatchDelay;  
  60.     }  
  61.   
  62.   
  63.   
  64.     public void init() throws ZoieException {  
  65.         //如果索引目录不存在则新建  
  66.         File idxDir = new File(userIndexPath);  
  67.         if(!idxDir.exists()){  
  68.             idxDir.mkdir();  
  69.         }  
  70.           
  71.         //分词器设置为ansj-seg分词器  
  72.         analyzer = new AnsjAnalyzer();  
  73.           
  74.         //数据转换器[JavaBea-->Document]  
  75.         ZoieIndexableInterpreter interpreter = new CustomPersonZoieIndexableInterpreter(analyzer);  
  76.         //Lucene的IndexReader装饰者,包装成zoie的IndexReader  
  77.         DefaultIndexReaderDecorator readerDecorator = new DefaultIndexReaderDecorator();  
  78.           
  79.         //Zoie初始化相关配置  
  80.         ZoieConfig zoieConfig = new ZoieConfig();  
  81.         zoieConfig.setBatchDelay(zoieBatchDelay);  
  82.         zoieConfig.setBatchSize(zoieBatchSize);  
  83.         //设置分词器  
  84.         zoieConfig.setAnalyzer(analyzer);  
  85.         //设置相似性评分器  
  86.         zoieConfig.setSimilarity(new DefaultSimilarity());  
  87.         // 开启NRT索引  
  88.         zoieConfig.setRtIndexing(true);  
  89.         zoieSystem = new ZoieSystem(idxDir, interpreter, readerDecorator, zoieConfig);  
  90.         zoieSystem.start();  
  91.         zoieSystem.getAdminMBean().flushToDiskIndex();  
  92.     }  
  93.       
  94.     /** 
  95.      * 更新索引数据 
  96.      * @throws ZoieException  
  97.      */  
  98.     public void updateIndexData() throws ZoieException {  
  99.         //先从数据库查出新增加的数据  
  100.         List<Person> persons = personDao.findPersonBefore3S();  
  101.         if(persons == null || persons.size() == 0) {  
  102.             System.out.println("No increment data right now.please wait a while.");  
  103.             return;  
  104.         }  
  105.         List<DataEvent<Person>> dataEventList = new ArrayList<DataEvent<Person>>();  
  106.         for(Person person : persons) {  
  107.             dataEventList.add(new DataEvent<Person>(person, "1.0", person.isDeleteFlag()));  
  108.         }  
  109.         //消费数据  
  110.         zoieSystem.consume(dataEventList);  
  111.     }  
  112.       
  113.     public void destroy(){  
  114.         // 将内存索引刷新到磁盘索引中  
  115.         zoieSystem.shutdown();   
  116.         System.out.println(".........将内存索引刷新到磁盘索引中.........");  
  117.     }  
  118.   
  119.     public String getUserIndexPath() {  
  120.         return userIndexPath;  
  121.     }  
  122.   
  123.     public void setUserIndexPath(String userIndexPath) {  
  124.         this.userIndexPath = userIndexPath;  
  125.     }  
  126.   
  127.     public int getZoieBatchSize() {  
  128.         return zoieBatchSize;  
  129.     }  
  130.   
  131.     public void setZoieBatchSize(int zoieBatchSize) {  
  132.         this.zoieBatchSize = zoieBatchSize;  
  133.     }  
  134.   
  135.     public int getZoieBatchDelay() {  
  136.         return zoieBatchDelay;  
  137.     }  
  138.   
  139.     public void setZoieBatchDelay(int zoieBatchDelay) {  
  140.         this.zoieBatchDelay = zoieBatchDelay;  
  141.     }  
  142.   
  143.     public Analyzer getAnalyzer() {  
  144.         return analyzer;  
  145.     }  
  146.   
  147.     public void setAnalyzer(Analyzer analyzer) {  
  148.         this.analyzer = analyzer;  
  149.     }  
  150.   
  151.     public PersonDao getPersonDao() {  
  152.         return personDao;  
  153.     }  
  154.   
  155.     public void setPersonDao(PersonDao personDao) {  
  156.         this.personDao = personDao;  
  157.     }  
  158. }  

    

Java代码   收藏代码
  1. package com.yida.framework.lucene5.incrementindex;  
  2.   
  3. import java.util.TimerTask;  
  4.   
  5. import proj.zoie.api.ZoieException;  
  6.   
  7. /** 
  8.  * Zoie定时增量索引任务 
  9.  * @author LANXIAOWEI 
  10.  * 
  11.  */  
  12. public class ZoieIndexTimerTask extends TimerTask {  
  13.     private ZoieIndex zoieIndex;  
  14.       
  15.     @Override  
  16.     public void run() {  
  17.         try {  
  18.             zoieIndex.init();  
  19.             zoieIndex.updateIndexData();  
  20.         } catch (ZoieException e) {  
  21.             e.printStackTrace();  
  22.         }  
  23.     }  
  24.   
  25.     public ZoieIndexTimerTask(ZoieIndex zoieIndex) {  
  26.         super();  
  27.         this.zoieIndex = zoieIndex;  
  28.     }  
  29.   
  30.     public ZoieIndex getZoieIndex() {  
  31.         return zoieIndex;  
  32.     }  
  33.   
  34.     public void setZoieIndex(ZoieIndex zoieIndex) {  
  35.         this.zoieIndex = zoieIndex;  
  36.     }  
  37. }  

   

Java代码   收藏代码
  1. package com.yida.framework.lucene5.incrementindex;  
  2.   
  3. import java.io.IOException;  
  4. import java.nio.file.Paths;  
  5. import java.util.ArrayList;  
  6. import java.util.List;  
  7.   
  8. import org.apache.lucene.document.Document;  
  9. import org.apache.lucene.index.DirectoryReader;  
  10. import org.apache.lucene.index.IndexReader;  
  11. import org.apache.lucene.index.Term;  
  12. import org.apache.lucene.search.IndexSearcher;  
  13. import org.apache.lucene.search.Query;  
  14. import org.apache.lucene.search.ScoreDoc;  
  15. import org.apache.lucene.search.TermQuery;  
  16. import org.apache.lucene.search.TopDocs;  
  17. import org.apache.lucene.search.WildcardQuery;  
  18. import org.apache.lucene.store.FSDirectory;  
  19.   
  20. /** 
  21.  * Zoie查询测试 
  22.  *  
  23.  * @author Lanxiaowei 
  24.  *  
  25.  */  
  26. public class ZoieSearchTest {  
  27.     public static void main(String[] args) throws IOException {  
  28.         // 参数定义  
  29.         String directoryPath = "C:/zoieindex";  
  30.         String fieldName = "nativePlace";  
  31.         String queryString = "*香港*";  
  32.   
  33.         Query query = new WildcardQuery(new Term(fieldName,queryString));  
  34.         List<Document> list = query(directoryPath,query);  
  35.         if (list == null || list.size() == 0) {  
  36.             System.out.println("No results found.");  
  37.             return;  
  38.         }  
  39.         for (Document doc : list) {  
  40.             String personName = doc.get("personName");  
  41.             String nativePlace = doc.get("nativePlace");  
  42.             String hobby = doc.get("hobby");  
  43.             System.out.println("personName:" + personName);  
  44.             System.out.println("nativePlace:" + nativePlace);  
  45.             System.out.println("hobby:" + hobby);  
  46.         }  
  47.     }  
  48.       
  49.     /** 
  50.      * 创建索引阅读器 
  51.      * @param directoryPath  索引目录 
  52.      * @return 
  53.      * @throws IOException   可能会抛出IO异常 
  54.      */  
  55.     public static IndexReader createIndexReader(String directoryPath) throws IOException {  
  56.         return DirectoryReader.open(FSDirectory.open(Paths.get(directoryPath, new String[0])));  
  57.     }  
  58.       
  59.     /** 
  60.      * 创建索引查询器 
  61.      * @param directoryPath   索引目录 
  62.      * @return 
  63.      * @throws IOException 
  64.      */  
  65.     public static IndexSearcher createIndexSearcher(String directoryPath) throws IOException {  
  66.         return new IndexSearcher(createIndexReader(directoryPath));  
  67.     }  
  68.       
  69.     /** 
  70.      * 创建索引查询器 
  71.      * @param reader 
  72.      * @return 
  73.      */  
  74.     public static IndexSearcher createIndexSearcher(IndexReader reader) {  
  75.         return new IndexSearcher(reader);  
  76.     }  
  77.       
  78.     public static List<Document> query(String directoryPath,Query query) throws IOException {  
  79.         IndexSearcher searcher = createIndexSearcher(directoryPath);  
  80.         TopDocs topDocs = searcher.search(query, Integer.MAX_VALUE);  
  81.         List<Document> docList = new ArrayList<Document>();  
  82.         ScoreDoc[] docs = topDocs.scoreDocs;  
  83.         for (ScoreDoc scoreDoc : docs) {  
  84.             int docID = scoreDoc.doc;  
  85.             Document document = searcher.doc(docID);  
  86.             docList.add(document);  
  87.         }  
  88.         searcher.getIndexReader().close();  
  89.         return docList;  
  90.     }  
  91. }  

   

Java代码   收藏代码
  1. package com.yida.framework.lucene5.incrementindex;  
  2.   
  3. import java.util.Timer;  
  4.   
  5. import org.ansj.lucene5.AnsjAnalyzer;  
  6. import org.apache.lucene.analysis.Analyzer;  
  7. /** 
  8.  * 增量索引测试 
  9.  * @author Lanxiaowei 
  10.  * 
  11.  */  
  12. public class ZoieTest {  
  13.     public static void main(String[] args) throws Exception {  
  14.           
  15.         String userIndexPath = "C:/zoieindex";  
  16.         Analyzer analyzer = new AnsjAnalyzer();  
  17.         PersonDao personDao = new PersonDaoImpl();  
  18.         int zoieBatchSize = 10;  
  19.         int zoieBatchDelay = 1000;  
  20.           
  21.         //先读取数据库表中已有数据创建索引  
  22.         CreateIndexTest createIndexTest = new CreateIndexTest(personDao, userIndexPath);  
  23.         createIndexTest.index();  
  24.           
  25.         //再往数据库表中插入一条数据,模拟数据动态变化  
  26.         PersonDaoTest.addPerson();  
  27.           
  28.           
  29.         ZoieIndex zoindex = new ZoieIndex(userIndexPath, analyzer, personDao,   
  30.             zoieBatchSize, zoieBatchDelay);  
  31.         Timer timer = new Timer("myTimer",false);  
  32.         timer.scheduleAtFixedRate(new ZoieIndexTimerTask(zoindex),10L,3000L);  
  33.           
  34.         //睡眠2分钟  
  35.         Thread.sleep(2*60*1000L);  
  36.         //2分钟后定时器取消  
  37.         timer.cancel();  
  38.         System.out.println("Timer cancled.");  
  39.           
  40.         /**把索引flush到硬盘*/  
  41.         zoindex.destroy();  
  42.         System.out.println("finished.");  
  43.     }  
  44. }  

   

Java代码   收藏代码
  1. package com.yida.framework.lucene5.incrementindex;  
  2.   
  3. import java.io.IOException;  
  4. import java.nio.file.Paths;  
  5. import java.util.List;  
  6.   
  7. import org.ansj.lucene5.AnsjAnalyzer;  
  8. import org.apache.lucene.analysis.Analyzer;  
  9. import org.apache.lucene.document.Document;  
  10. import org.apache.lucene.document.Field;  
  11. import org.apache.lucene.document.IntField;  
  12. import org.apache.lucene.document.LongField;  
  13. import org.apache.lucene.document.NumericDocValuesField;  
  14. import org.apache.lucene.document.StringField;  
  15. import org.apache.lucene.document.TextField;  
  16. import org.apache.lucene.index.IndexWriter;  
  17. import org.apache.lucene.index.IndexWriterConfig;  
  18. import org.apache.lucene.index.IndexWriterConfig.OpenMode;  
  19. import org.apache.lucene.store.Directory;  
  20. import org.apache.lucene.store.FSDirectory;  
  21.   
  22. import com.yida.framework.lucene5.util.LuceneUtils;  
  23.   
  24. /** 
  25.  * 读取数据库表中数据创建索引 
  26.  * @author Lanxiaowei 
  27.  * 
  28.  */  
  29. public class CreateIndexTest {  
  30.     private PersonDao personDao;  
  31.     /**索引目录*/  
  32.     private String indexDir;  
  33.       
  34.     public static void main(String[] args) throws IOException {  
  35.         String userIndexPath = "C:/zoieindex";  
  36.         PersonDao personDao = new PersonDaoImpl();  
  37.         //先读取数据库表中已有数据创建索引  
  38.         CreateIndexTest createIndexTest = new CreateIndexTest(personDao, userIndexPath);  
  39.         createIndexTest.index();  
  40.     }  
  41.       
  42.     public CreateIndexTest(PersonDao personDao, String indexDir) {  
  43.         super();  
  44.         this.personDao = personDao;  
  45.         this.indexDir = indexDir;  
  46.     }  
  47.   
  48.     public void index() throws IOException {  
  49.         List<Person> persons = personDao.findAll();  
  50.         if(null == persons || persons.size() == 0) {  
  51.             return;  
  52.         }  
  53.         Directory dir = FSDirectory.open(Paths.get(indexDir));  
  54.         Analyzer analyzer = new AnsjAnalyzer();  
  55.         IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);  
  56.         indexWriterConfig.setOpenMode(OpenMode.CREATE_OR_APPEND);  
  57.         IndexWriter writer = new IndexWriter(dir, indexWriterConfig);  
  58.         for(Person person : persons) {  
  59.             Document document = new Document();  
  60.             document.add(new Field("id",person.getId().toString(),Field.Store.YES,  
  61.                 Field.Index.NOT_ANALYZED,Field.TermVector.NO));  
  62.             document.add(new StringField("personName", person.getPersonName(), Field.Store.YES));  
  63.             document.add(new StringField("sex", person.getSex(), Field.Store.YES));  
  64.             document.add(new LongField("birth", person.getBirth().getTime(), Field.Store.YES));  
  65.             document.add(new TextField("nativePlace", person.getNativePlace(), Field.Store.YES));  
  66.             document.add(new StringField("job", person.getJob(), Field.Store.YES));  
  67.             document.add(new IntField("salary", person.getSalary(), Field.Store.YES));  
  68.             document.add(new StringField("hobby", person.getHobby(), Field.Store.YES));  
  69.             document.add(new StringField("deleteFlag", person.isDeleteFlag() + "", Field.Store.YES));  
  70.             //Zoie需要的UID[注意:这个域必须加,且必须是NumericDocValuesField类型,至于UID的域值是什么没关系,只要保证它是唯一的即可]  
  71.             document.add(new NumericDocValuesField("_ID", person.getId()));  
  72.             LuceneUtils.addIndex(writer, document);  
  73.         }  
  74.         writer.close();  
  75.         dir.close();  
  76.     }  
  77. }  

   

Java代码   收藏代码
  1. package com.yida.framework.lucene5.incrementindex;  
  2.   
  3. import javax.sql.DataSource;  
  4.   
  5. import org.apache.commons.dbcp.BasicDataSource;  
  6. import org.apache.commons.dbutils.QueryRunner;  
  7.   
  8. public class DBHelper {  
  9.     private static DataSource dataSource;  
  10.       
  11.     public static QueryRunner getQueryRunner(){  
  12.         if(DBHelper.dataSource == null){  
  13.             BasicDataSource dbcpDataSource = new BasicDataSource();  
  14.             dbcpDataSource.setUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&amp;characterEncoding=utf8");  
  15.             dbcpDataSource.setDriverClassName("com.mysql.jdbc.Driver");  
  16.             dbcpDataSource.setUsername("root");  
  17.             dbcpDataSource.setPassword("123");  
  18.             dbcpDataSource.setDefaultAutoCommit(true);  
  19.             dbcpDataSource.setMaxActive(100);  
  20.             dbcpDataSource.setMaxIdle(30);  
  21.             dbcpDataSource.setMaxWait(500);  
  22.             DBHelper.dataSource = (DataSource)dbcpDataSource;  
  23.         }  
  24.         return new QueryRunner(DBHelper.dataSource);  
  25.     }  
  26. }  

    

Java代码   收藏代码
  1. package com.yida.framework.lucene5.incrementindex;  
  2.   
  3. import org.apache.lucene.analysis.Analyzer;  
  4.   
  5. import proj.zoie.api.indexing.AbstractZoieIndexableInterpreter;  
  6. import proj.zoie.api.indexing.ZoieIndexable;  
  7.   
  8. /** 
  9.  * 自定义Person-->Document的数据转换器的生产者 
  10.  * @author Lanxiaowei 
  11.  * 
  12.  */  
  13. public class CustomPersonZoieIndexableInterpreter extends AbstractZoieIndexableInterpreter<Person>{  
  14.     private Analyzer analyzer;  
  15.       
  16.     @Override  
  17.     public ZoieIndexable convertAndInterpret(Person person) {  
  18.         return new PersonZoieIndexable(person, analyzer);  
  19.     }  
  20.       
  21.     public CustomPersonZoieIndexableInterpreter() {}  
  22.       
  23.     public CustomPersonZoieIndexableInterpreter(Analyzer analyzer) {  
  24.         super();  
  25.         this.analyzer = analyzer;  
  26.     }  
  27.   
  28.     public Analyzer getAnalyzer() {  
  29.         return analyzer;  
  30.     }  
  31.     public void setAnalyzer(Analyzer analyzer) {  
  32.         this.analyzer = analyzer;  
  33.     }  
  34. }  

   

Java代码   收藏代码
  1. package com.yida.framework.lucene5.incrementindex;  
  2.   
  3. import org.apache.lucene.analysis.Analyzer;  
  4. import org.apache.lucene.document.Document;  
  5. import org.apache.lucene.document.Field;  
  6. import org.apache.lucene.document.IntField;  
  7. import org.apache.lucene.document.LongField;  
  8. import org.apache.lucene.document.StringField;  
  9. import org.apache.lucene.document.TextField;  
  10.   
  11. import proj.zoie.api.indexing.AbstractZoieIndexable;  
  12. /** 
  13.  * JavaBean与Document的转换器 
  14.  * @author Lanxiaowei 
  15.  * 
  16.  */  
  17. public class PersonZoieIndexable extends AbstractZoieIndexable {  
  18.     private Person person;  
  19.     private Analyzer analyzer;  
  20.   
  21.     public PersonZoieIndexable(Person person) {  
  22.         super();  
  23.         this.person = person;  
  24.     }  
  25.   
  26.     public PersonZoieIndexable(Person person, Analyzer analyzer) {  
  27.         super();  
  28.         this.person = person;  
  29.         this.analyzer = analyzer;  
  30.     }  
  31.   
  32.     public Document buildDocument() {  
  33.         System.out.println("Person --> Document begining.");  
  34.         Document document = new Document();  
  35.         document.add(new Field("id",person.getId().toString(),Field.Store.YES,  
  36.             Field.Index.NOT_ANALYZED,Field.TermVector.NO));  
  37.         document.add(new StringField("personName", person.getPersonName(), Field.Store.YES));  
  38.         document.add(new StringField("sex", person.getSex(), Field.Store.YES));  
  39.         document.add(new LongField("birth", person.getBirth().getTime(), Field.Store.YES));  
  40.         document.add(new TextField("nativePlace", person.getNativePlace(), Field.Store.YES));  
  41.         document.add(new StringField("job", person.getJob(), Field.Store.YES));  
  42.         document.add(new IntField("salary", person.getSalary(), Field.Store.YES));  
  43.         document.add(new StringField("hobby", person.getHobby(), Field.Store.YES));  
  44.         document.add(new StringField("deleteFlag", person.isDeleteFlag() + "", Field.Store.YES));  
  45.         return document;  
  46.     }  
  47.   
  48.     @Override  
  49.     public IndexingReq[] buildIndexingReqs() {  
  50.         return new IndexingReq[] {new IndexingReq(buildDocument(), analyzer)};  
  51.     }  
  52.   
  53.     @Override  
  54.     public long getUID() {  
  55.         return person.getId();  
  56.     }  
  57.   
  58.     @Override  
  59.     public boolean isDeleted() {  
  60.         return person.isDeleteFlag();  
  61.     }  
  62.       
  63.     public Analyzer getAnalyzer() {  
  64.         return analyzer;  
  65.     }  
  66.   
  67.     public void setAnalyzer(Analyzer analyzer) {  
  68.         this.analyzer = analyzer;  
  69.     }  
  70. }  

   

Java代码   收藏代码
  1. package com.yida.framework.lucene5.incrementindex;  
  2.   
  3. import java.util.Date;  
  4.   
  5. public class Person {  
  6.     private Long id;  
  7.     private String personName;  
  8.     /**性别:1(男)/0(女)*/  
  9.     private String sex;  
  10.     private Date birth;  
  11.     /**籍贯*/  
  12.     private String nativePlace;  
  13.     private String job;  
  14.     private Integer salary;  
  15.     /**兴趣爱好*/  
  16.     private String hobby;  
  17.       
  18.     /**删除标记: true已删除/false未删除*/  
  19.     private boolean deleteFlag;  
  20.     /**最后一次更新时间*/  
  21.     private Date updatedTime;  
  22.       
  23.     public Person() {}  
  24.       
  25.       
  26.       
  27.     public Person(String personName, String sex, Date birth,  
  28.             String nativePlace, String job, Integer salary, String hobby) {  
  29.         super();  
  30.         this.personName = personName;  
  31.         this.sex = sex;  
  32.         this.birth = birth;  
  33.         this.nativePlace = nativePlace;  
  34.         this.job = job;  
  35.         this.salary = salary;  
  36.         this.hobby = hobby;  
  37.     }  
  38.       
  39.     public Person(String personName, String sex, Date birth,  
  40.             String nativePlace, String job, Integer salary, String hobby,boolean deleteFlag) {  
  41.         super();  
  42.         this.personName = personName;  
  43.         this.sex = sex;  
  44.         this.birth = birth;  
  45.         this.nativePlace = nativePlace;  
  46.         this.job = job;  
  47.         this.salary = salary;  
  48.         this.hobby = hobby;  
  49.         this.deleteFlag = deleteFlag;  
  50.     }  
  51.   
  52.     public Person(String personName, String sex, Date birth,  
  53.             String nativePlace, String job, Integer salary, String hobby,  
  54.             boolean deleteFlag, Date updatedTime) {  
  55.         super();  
  56.         this.personName = personName;  
  57.         this.sex = sex;  
  58.         this.birth = birth;  
  59.         this.nativePlace = nativePlace;  
  60.         this.job = job;  
  61.         this.salary = salary;  
  62.         this.hobby = hobby;  
  63.         this.deleteFlag = deleteFlag;  
  64.         this.updatedTime = updatedTime;  
  65.     }  
  66.   
  67.     public Long getId() {  
  68.         return id;  
  69.     }  
  70.     public void setId(Long id) {  
  71.         this.id = id;  
  72.     }  
  73.     public String getPersonName() {  
  74.         return personName;  
  75.     }  
  76.     public void setPersonName(String personName) {  
  77.         this.personName = personName;  
  78.     }  
  79.     public String getSex() {  
  80.         return sex;  
  81.     }  
  82.     public void setSex(String sex) {  
  83.         this.sex = sex;  
  84.     }  
  85.     public Date getBirth() {  
  86.         return birth;  
  87.     }  
  88.     public void setBirth(Date birth) {  
  89.         this.birth = birth;  
  90.     }  
  91.     public String getNativePlace() {  
  92.         return nativePlace;  
  93.     }  
  94.     public void setNativePlace(String nativePlace) {  
  95.         this.nativePlace = nativePlace;  
  96.     }  
  97.     public String getJob() {  
  98.         return job;  
  99.     }  
  100.     public void setJob(String job) {  
  101.         this.job = job;  
  102.     }  
  103.     public Integer getSalary() {  
  104.         return salary;  
  105.     }  
  106.     public void setSalary(Integer salary) {  
  107.         this.salary = salary;  
  108.     }  
  109.     public String getHobby() {  
  110.         return hobby;  
  111.     }  
  112.     public void setHobby(String hobby) {  
  113.         this.hobby = hobby;  
  114.     }  
  115.   
  116.     public boolean isDeleteFlag() {  
  117.         return deleteFlag;  
  118.     }  
  119.   
  120.     public void setDeleteFlag(boolean deleteFlag) {  
  121.         this.deleteFlag = deleteFlag;  
  122.     }  
  123.   
  124.     public Date getUpdatedTime() {  
  125.         return updatedTime;  
  126.     }  
  127.   
  128.     public void setUpdatedTime(Date updatedTime) {  
  129.         this.updatedTime = updatedTime;  
  130.     }  
  131.   
  132.   
  133.   
  134.     @Override  
  135.     public int hashCode() {  
  136.         final int prime = 31;  
  137.         int result = 1;  
  138.         result = prime * result + ((id == null) ? 0 : id.hashCode());  
  139.         return result;  
  140.     }  
  141.   
  142.     @Override  
  143.     public boolean equals(Object obj) {  
  144.         if (this == obj)  
  145.             return true;  
  146.         if (obj == null)  
  147.             return false;  
  148.         if (getClass() != obj.getClass())  
  149.             return false;  
  150.         Person other = (Person) obj;  
  151.         if (id == null) {  
  152.             if (other.id != null)  
  153.                 return false;  
  154.         } else if (!id.equals(other.id))  
  155.             return false;  
  156.         return true;  
  157.     }  
  158. }  

   

Java代码   收藏代码
  1. package com.yida.framework.lucene5.incrementindex;  
  2.   
  3. import java.util.List;  
  4.   
  5. public interface PersonDao {  
  6.     /** 
  7.      * 新增 
  8.      * @return 
  9.      */  
  10.     public boolean save(Person person);  
  11.       
  12.     /** 
  13.      * 更新 
  14.      * @param person 
  15.      * @return 
  16.      */  
  17.     public boolean update(Person person);  
  18.       
  19.     /** 
  20.      * 根据ID删除 
  21.      * @param id 
  22.      * @return 
  23.      */  
  24.     public boolean delete(Long id);  
  25.       
  26.     /** 
  27.      * 根据ID查询 
  28.      * @param id 
  29.      * @return 
  30.      */  
  31.     public Person findById(Long id);  
  32.       
  33.     /** 
  34.      * 查询所有 
  35.      * @return 
  36.      */  
  37.     public List<Person> findAll();  
  38.       
  39.     /** 
  40.      * 查询3秒之前的数据,用于测试 
  41.      * @return 
  42.      */  
  43.     public List<Person> findPersonBefore3S();  
  44. }  

   

Java代码   收藏代码
  1. package com.yida.framework.lucene5.incrementindex;  
  2.   
  3. import java.sql.SQLException;  
  4. import java.util.Date;  
  5. import java.util.List;  
  6.   
  7. import org.apache.commons.dbutils.QueryRunner;  
  8. import org.apache.commons.dbutils.handlers.BeanHandler;  
  9. import org.apache.commons.dbutils.handlers.BeanListHandler;  
  10.   
  11. public class PersonDaoImpl implements PersonDao {  
  12.     private QueryRunner queryRunner = DBHelper.getQueryRunner();  
  13.     /** 
  14.      * 新增 
  15.      * @return 
  16.      */  
  17.     public boolean save(Person person) {  
  18.         int result = 0;  
  19.         try {  
  20.             result = queryRunner.update("insert into person(personName,sex,birth,nativePlace,job,salary,hobby,deleteFlag,updatedTime) " +   
  21.                     "values(?,?,?,?,?,?,?,?,?)" , new Object[] {  
  22.                     person.getPersonName(),  
  23.                     person.getSex(),  
  24.                     person.getBirth(),  
  25.                     person.getNativePlace(),  
  26.                     person.getJob(),  
  27.                     person.getSalary(),  
  28.                     person.getHobby(),  
  29.                     person.isDeleteFlag(),  
  30.                     new Date()  
  31.             });  
  32.         } catch (SQLException e) {  
  33.             e.printStackTrace();  
  34.         }  
  35.         return result == 1;  
  36.     }  
  37.       
  38.     /** 
  39.      * 根据ID更新 
  40.      * @param person 
  41.      * @return 
  42.      */  
  43.     public boolean update(Person person) {  
  44.         int result = 0;  
  45.         try {  
  46.             result = queryRunner.update(  
  47.                     "update person set personName = ?, sex = ?, birth = ?, " +   
  48.                     "nativePlace = ?, job = ?, salary = ?, hobby = ?,deleteFlag = ?, " +  
  49.                     "updatedTime = ? where id = ?"   
  50.                     , new Object[] {  
  51.                     person.getPersonName(),  
  52.                     person.getSex(),  
  53.                     person.getBirth(),  
  54.                     person.getNativePlace(),  
  55.                     person.getJob(),  
  56.                     person.getSalary(),  
  57.                     person.getHobby(),  
  58.                     person.isDeleteFlag(),  
  59.                     new Date(),  
  60.                     person.getId()  
  61.             });  
  62.         } catch (SQLException e) {  
  63.             e.printStackTrace();  
  64.         }  
  65.         return result == 1;  
  66.     }  
  67.       
  68.     /** 
  69.      * 根据ID删除 
  70.      * @param id 
  71.      * @return 
  72.      */  
  73.     public boolean delete(Long id) {  
  74.         int result = 0;  
  75.         try {  
  76.             result = queryRunner.update("delete from person where id = ?", id);  
  77.         } catch (SQLException e) {  
  78.             e.printStackTrace();  
  79.         }  
  80.         return result == 1;  
  81.     }  
  82.       
  83.     /** 
  84.      * 根据ID查询 
  85.      * @param id 
  86.      * @return 
  87.      */  
  88.     public Person findById(Long id) {  
  89.         Person person = null;  
  90.         try {  
  91.             person = queryRunner.query("select * from person where id = ?"new BeanHandler<Person>(Person.class),id);  
  92.         } catch (SQLException e) {  
  93.             e.printStackTrace();  
  94.         }  
  95.         return person;  
  96.     }  
  97.       
  98.     /** 
  99.      * 查询所有 
  100.      * @return 
  101.      */  
  102.     public List<Person> findAll() {  
  103.         List<Person> persons = null;  
  104.         try {  
  105.             persons = queryRunner.query("select * from person"new BeanListHandler<Person>(Person.class));  
  106.         } catch (SQLException e) {  
  107.             e.printStackTrace();  
  108.         }  
  109.         return persons;  
  110.     }  
  111.       
  112.     /** 
  113.      * 查询3秒之前的数据,用于测试 
  114.      * @return 
  115.      */  
  116.     public List<Person> findPersonBefore3S() {  
  117.         List<Person> persons = null;  
  118.         try {  
  119.             persons = queryRunner.query("select * from person where updatedTime >= DATE_SUB(NOW(),INTERVAL 3 SECOND)"new BeanListHandler<Person>(Person.class));  
  120.         } catch (SQLException e) {  
  121.             e.printStackTrace();  
  122.         }  
  123.         return persons;  
  124.     }  
  125. }  

   

Java代码   收藏代码
  1. package com.yida.framework.lucene5.incrementindex;  
  2.   
  3. import java.text.DateFormat;  
  4. import java.text.ParseException;  
  5. import java.text.SimpleDateFormat;  
  6. import java.util.Date;  
  7.   
  8. /** 
  9.  * PersonDao测试 
  10.  * @author Lanxiaowei 
  11.  * 
  12.  */  
  13. public class PersonDaoTest {  
  14.     private static final DateFormat dateFormate = new SimpleDateFormat("yyyy-MM-dd");  
  15.     public static void main(String[] args) throws Exception {  
  16.         addPerson();  
  17.           
  18.     }  
  19.       
  20.     /** 
  21.      * 添加一个Person测试 
  22.      * @throws ParseException 
  23.      */  
  24.     public static void addPerson() throws ParseException {  
  25.         PersonDao personDao = new PersonDaoImpl();  
  26.         String personName = "张国荣";  
  27.         String sex = "1";  
  28.         String birthString = "1956-09-12";  
  29.         Date birth = dateFormate.parse(birthString);  
  30.         String nativePlace = "中国香港九龙";  
  31.         String job = "歌手";  
  32.         Integer salary = 16000;  
  33.         String hobby = "演员&音乐";  
  34.         boolean deleteFlag = false;  
  35.         Person person = new Person(personName, sex, birth, nativePlace, job, salary, hobby, deleteFlag);  
  36.         boolean success = personDao.save(person);  
  37.         System.out.println(success ? "Person save successful." : "Person save fauilure.");  
  38.     }  
  39. }  

   数据库建表SQL:

Sql代码   收藏代码
  1. CREATE TABLE `person` (  
  2.   `id` bigint(20) NOT NULL AUTO_INCREMENT,  
  3.   `personName` varchar(60) DEFAULT NULL,  
  4.   `sex` char(1) DEFAULT NULL,  
  5.   `birth` datetime DEFAULT NULL,  
  6.   `nativePlace` varchar(200) DEFAULT NULL,  
  7.   `job` varchar(60) DEFAULT NULL,  
  8.   `salary` int(11) DEFAULT NULL,  
  9.   `hobby` varchar(200) DEFAULT NULL,  
  10.   `deleteFlag` bit(1) DEFAULT NULL,  
  11.   `updatedTime` datetime DEFAULT NULL,  
  12.   PRIMARY KEY (`id`)  
  13. ) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;  
  14.   
  15.   
  16. INSERT INTO `person` VALUES (1, '兰小伟''1''1987-6-5 00:00:00''湖北省武穴市''码农', 16000, '看书写代码听歌看电影玩玩CS看看斯诺克比赛''''2015-4-6 18:01:30');  
  17. INSERT INTO `person` VALUES (2, '李小龙''1''1940-2-26 00:00:00''中国广东顺德均安镇''武术大师', 16000, '武术&音乐''''2015-4-6 18:14:04');  

   建表SQL文件和demo源码我会在底下的附件里上传,自己去下载。SQL文件怎么导入到MySQL我就不多说了哈,如果这个你不会,请自己Google。运行ZoieTest类进行测试,在运行之前,请先打开DBHelper工具类,修改里面的MySQL数据库的帐号密码,因为你的MySQL登录帐号密码可能跟我的不一样,还有记得把Zoie-core的jar包install到本地仓库,否则你maven的pom.xml会报错。运行ZoieTest测试类之后,你就可以不断运行ZoieSearchTest测试来查询数据,来查看新增的数据是否已经被索引且能被搜索到。

    

   如果你还有什么问题请加我Q-Q:7-3-6-0-3-1-3-0-5,

或者加裙
一起交流学习!

转载:http://iamyida.iteye.com/blog/2199848

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
7月前
|
存储 自然语言处理 关系型数据库
ElasticSearch索引 和MySQL索引那个更高效实用那个更合适
ElasticSearch索引 和MySQL索引那个更高效实用那个更合适
84 0
|
SQL 数据库 索引
08Lucene索引库查询 - 介绍
08Lucene索引库查询 - 介绍
59 0
|
存储 自然语言处理 索引
05Lucene索引库的添加
05Lucene索引库的添加
42 0
|
索引
06Lucene索引库的删除
06Lucene索引库的删除
44 0
|
索引
07Lucene索引库的修改
07Lucene索引库的修改
37 0
|
存储 自然语言处理 关系型数据库
Lucene的查询过程
Lucene的查询过程
198 0
|
存储 自然语言处理 数据库
Lucene 查询原理
# 前言 Lucene 是一个基于 Java 的全文信息检索工具包,目前主流的搜索系统Elasticsearch和solr都是基于lucene的索引和搜索能力进行。想要理解搜索系统的实现原理,就需要深入lucene这一层,看看lucene是如何存储需要检索的数据,以及如何完成高效的数据检索。
8649 1