`
lxwt909
  • 浏览: 566740 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Lucene5学习之增量索引(Zoie)

阅读更多

      清明节放假期间,就一直在思考着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,示例程序就是模拟数据库表数据动态插入新数据后,能立马被准实时被索引到,且被搜索到。下面就直接上代码了:

    

package com.yida.framework.lucene5.incrementindex;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.ansj.lucene5.AnsjAnalyzer;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.search.similarities.DefaultSimilarity;

import proj.zoie.api.DataConsumer.DataEvent;
import proj.zoie.api.ZoieException;
import proj.zoie.api.indexing.ZoieIndexableInterpreter;
import proj.zoie.impl.indexing.DefaultIndexReaderDecorator;
import proj.zoie.impl.indexing.ZoieConfig;
import proj.zoie.impl.indexing.ZoieSystem;

/**
 * Zoie增量索引测试
 * @author Lanxiaowei
 *
 */
@SuppressWarnings({"unchecked","rawtypes"})
public class ZoieIndex {
	
	/**最大增量索引数量*/
	public static final long MAX_INCREMENT_INDEX_NUMBER = Long.MAX_VALUE;
	/**索引目录*/
	public String userIndexPath;
	
	public ZoieSystem zoieSystem;
	
	/**队列中放入多少项才触发索引*/
	private  int zoieBatchSize;
	
	/**等待多长时间才触发索引*/
	private int zoieBatchDelay;
    
    /**分词器*/
    private Analyzer analyzer;
    
    private PersonDao personDao;
    
	public ZoieIndex(String userIndexPath, Analyzer analyzer,
			PersonDao personDao) {
		super();
		this.userIndexPath = userIndexPath;
		this.analyzer = analyzer;
		this.personDao = personDao;
	}

	public ZoieIndex(String userIndexPath, Analyzer analyzer,
			PersonDao personDao, int zoieBatchSize, int zoieBatchDelay) {
		super();
		this.userIndexPath = userIndexPath;
		this.analyzer = analyzer;
		this.personDao = personDao;
		this.zoieBatchSize = zoieBatchSize;
		this.zoieBatchDelay = zoieBatchDelay;
	}



	public void init() throws ZoieException {
    	//如果索引目录不存在则新建
    	File idxDir = new File(userIndexPath);
        if(!idxDir.exists()){
            idxDir.mkdir();
        }
        
        //分词器设置为ansj-seg分词器
        analyzer = new AnsjAnalyzer();
        
        //数据转换器[JavaBea-->Document]
        ZoieIndexableInterpreter interpreter = new CustomPersonZoieIndexableInterpreter(analyzer);
        //Lucene的IndexReader装饰者,包装成zoie的IndexReader
        DefaultIndexReaderDecorator readerDecorator = new DefaultIndexReaderDecorator();
        
        //Zoie初始化相关配置
        ZoieConfig zoieConfig = new ZoieConfig();
        zoieConfig.setBatchDelay(zoieBatchDelay);
        zoieConfig.setBatchSize(zoieBatchSize);
        //设置分词器
        zoieConfig.setAnalyzer(analyzer);
        //设置相似性评分器
        zoieConfig.setSimilarity(new DefaultSimilarity());
        // 开启NRT索引
        zoieConfig.setRtIndexing(true);
        zoieSystem = new ZoieSystem(idxDir, interpreter, readerDecorator, zoieConfig);
        zoieSystem.start();
        zoieSystem.getAdminMBean().flushToDiskIndex();
    }
	
	/**
	 * 更新索引数据
	 * @throws ZoieException 
	 */
	public void updateIndexData() throws ZoieException {
		//先从数据库查出新增加的数据
		List<Person> persons = personDao.findPersonBefore3S();
		if(persons == null || persons.size() == 0) {
			System.out.println("No increment data right now.please wait a while.");
			return;
		}
		List<DataEvent<Person>> dataEventList = new ArrayList<DataEvent<Person>>();
		for(Person person : persons) {
			dataEventList.add(new DataEvent<Person>(person, "1.0", person.isDeleteFlag()));
		}
		//消费数据
		zoieSystem.consume(dataEventList);
	}
	
	public void destroy(){
		// 将内存索引刷新到磁盘索引中
        zoieSystem.shutdown(); 
        System.out.println(".........将内存索引刷新到磁盘索引中.........");
    }

	public String getUserIndexPath() {
		return userIndexPath;
	}

	public void setUserIndexPath(String userIndexPath) {
		this.userIndexPath = userIndexPath;
	}

	public int getZoieBatchSize() {
		return zoieBatchSize;
	}

	public void setZoieBatchSize(int zoieBatchSize) {
		this.zoieBatchSize = zoieBatchSize;
	}

	public int getZoieBatchDelay() {
		return zoieBatchDelay;
	}

	public void setZoieBatchDelay(int zoieBatchDelay) {
		this.zoieBatchDelay = zoieBatchDelay;
	}

	public Analyzer getAnalyzer() {
		return analyzer;
	}

	public void setAnalyzer(Analyzer analyzer) {
		this.analyzer = analyzer;
	}

	public PersonDao getPersonDao() {
		return personDao;
	}

	public void setPersonDao(PersonDao personDao) {
		this.personDao = personDao;
	}
}

    

package com.yida.framework.lucene5.incrementindex;

import java.util.TimerTask;

import proj.zoie.api.ZoieException;

/**
 * Zoie定时增量索引任务
 * @author LANXIAOWEI
 *
 */
public class ZoieIndexTimerTask extends TimerTask {
	private ZoieIndex zoieIndex;
	
	@Override
	public void run() {
		try {
			zoieIndex.init();
			zoieIndex.updateIndexData();
		} catch (ZoieException e) {
			e.printStackTrace();
		}
	}

	public ZoieIndexTimerTask(ZoieIndex zoieIndex) {
		super();
		this.zoieIndex = zoieIndex;
	}

	public ZoieIndex getZoieIndex() {
		return zoieIndex;
	}

	public void setZoieIndex(ZoieIndex zoieIndex) {
		this.zoieIndex = zoieIndex;
	}
}

   

package com.yida.framework.lucene5.incrementindex;

import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.WildcardQuery;
import org.apache.lucene.store.FSDirectory;

/**
 * Zoie查询测试
 * 
 * @author Lanxiaowei
 * 
 */
public class ZoieSearchTest {
	public static void main(String[] args) throws IOException {
		// 参数定义
		String directoryPath = "C:/zoieindex";
		String fieldName = "nativePlace";
		String queryString = "*香港*";

		Query query = new WildcardQuery(new Term(fieldName,queryString));
		List<Document> list = query(directoryPath,query);
		if (list == null || list.size() == 0) {
			System.out.println("No results found.");
			return;
		}
		for (Document doc : list) {
			String personName = doc.get("personName");
			String nativePlace = doc.get("nativePlace");
			String hobby = doc.get("hobby");
			System.out.println("personName:" + personName);
			System.out.println("nativePlace:" + nativePlace);
			System.out.println("hobby:" + hobby);
		}
	}
	
	/**
	 * 创建索引阅读器
	 * @param directoryPath  索引目录
	 * @return
	 * @throws IOException   可能会抛出IO异常
	 */
	public static IndexReader createIndexReader(String directoryPath) throws IOException {
		return DirectoryReader.open(FSDirectory.open(Paths.get(directoryPath, new String[0])));
	}
	
	/**
	 * 创建索引查询器
	 * @param directoryPath   索引目录
	 * @return
	 * @throws IOException
	 */
	public static IndexSearcher createIndexSearcher(String directoryPath) throws IOException {
		return new IndexSearcher(createIndexReader(directoryPath));
	}
	
	/**
	 * 创建索引查询器
	 * @param reader
	 * @return
	 */
	public static IndexSearcher createIndexSearcher(IndexReader reader) {
		return new IndexSearcher(reader);
	}
	
	public static List<Document> query(String directoryPath,Query query) throws IOException {
		IndexSearcher searcher = createIndexSearcher(directoryPath);
		TopDocs topDocs = searcher.search(query, Integer.MAX_VALUE);
		List<Document> docList = new ArrayList<Document>();
		ScoreDoc[] docs = topDocs.scoreDocs;
		for (ScoreDoc scoreDoc : docs) {
			int docID = scoreDoc.doc;
			Document document = searcher.doc(docID);
			docList.add(document);
		}
		searcher.getIndexReader().close();
		return docList;
	}
}

   

package com.yida.framework.lucene5.incrementindex;

import java.util.Timer;

import org.ansj.lucene5.AnsjAnalyzer;
import org.apache.lucene.analysis.Analyzer;
/**
 * 增量索引测试
 * @author Lanxiaowei
 *
 */
public class ZoieTest {
	public static void main(String[] args) throws Exception {
		
		String userIndexPath = "C:/zoieindex";
		Analyzer analyzer = new AnsjAnalyzer();
		PersonDao personDao = new PersonDaoImpl();
		int zoieBatchSize = 10;
		int zoieBatchDelay = 1000;
		
		//先读取数据库表中已有数据创建索引
		CreateIndexTest createIndexTest = new CreateIndexTest(personDao, userIndexPath);
		createIndexTest.index();
		
		//再往数据库表中插入一条数据,模拟数据动态变化
		PersonDaoTest.addPerson();
		
		
		ZoieIndex zoindex = new ZoieIndex(userIndexPath, analyzer, personDao, 
			zoieBatchSize, zoieBatchDelay);
		Timer timer = new Timer("myTimer",false);
		timer.scheduleAtFixedRate(new ZoieIndexTimerTask(zoindex),10L,3000L);
		
		//睡眠2分钟
		Thread.sleep(2*60*1000L);
		//2分钟后定时器取消
		timer.cancel();
		System.out.println("Timer cancled.");
		
		/**把索引flush到硬盘*/
		zoindex.destroy();
		System.out.println("finished.");
	}
}

   

package com.yida.framework.lucene5.incrementindex;

import java.io.IOException;
import java.nio.file.Paths;
import java.util.List;

import org.ansj.lucene5.AnsjAnalyzer;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.IntField;
import org.apache.lucene.document.LongField;
import org.apache.lucene.document.NumericDocValuesField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;

import com.yida.framework.lucene5.util.LuceneUtils;

/**
 * 读取数据库表中数据创建索引
 * @author Lanxiaowei
 *
 */
public class CreateIndexTest {
	private PersonDao personDao;
	/**索引目录*/
	private String indexDir;
	
	public static void main(String[] args) throws IOException {
		String userIndexPath = "C:/zoieindex";
		PersonDao personDao = new PersonDaoImpl();
		//先读取数据库表中已有数据创建索引
		CreateIndexTest createIndexTest = new CreateIndexTest(personDao, userIndexPath);
		createIndexTest.index();
	}
	
	public CreateIndexTest(PersonDao personDao, String indexDir) {
		super();
		this.personDao = personDao;
		this.indexDir = indexDir;
	}

	public void index() throws IOException {
		List<Person> persons = personDao.findAll();
		if(null == persons || persons.size() == 0) {
			return;
		}
		Directory dir = FSDirectory.open(Paths.get(indexDir));
		Analyzer analyzer = new AnsjAnalyzer();
		IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
		indexWriterConfig.setOpenMode(OpenMode.CREATE_OR_APPEND);
		IndexWriter writer = new IndexWriter(dir, indexWriterConfig);
		for(Person person : persons) {
			Document document = new Document();
			document.add(new Field("id",person.getId().toString(),Field.Store.YES,
				Field.Index.NOT_ANALYZED,Field.TermVector.NO));
			document.add(new StringField("personName", person.getPersonName(), Field.Store.YES));
			document.add(new StringField("sex", person.getSex(), Field.Store.YES));
			document.add(new LongField("birth", person.getBirth().getTime(), Field.Store.YES));
			document.add(new TextField("nativePlace", person.getNativePlace(), Field.Store.YES));
			document.add(new StringField("job", person.getJob(), Field.Store.YES));
			document.add(new IntField("salary", person.getSalary(), Field.Store.YES));
			document.add(new StringField("hobby", person.getHobby(), Field.Store.YES));
			document.add(new StringField("deleteFlag", person.isDeleteFlag() + "", Field.Store.YES));
			//Zoie需要的UID[注意:这个域必须加,且必须是NumericDocValuesField类型,至于UID的域值是什么没关系,只要保证它是唯一的即可]
			document.add(new NumericDocValuesField("_ID", person.getId()));
			LuceneUtils.addIndex(writer, document);
		}
		writer.close();
		dir.close();
	}
}

   

package com.yida.framework.lucene5.incrementindex;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbutils.QueryRunner;

public class DBHelper {
	private static DataSource dataSource;
	
	public static QueryRunner getQueryRunner(){
        if(DBHelper.dataSource == null){
            BasicDataSource dbcpDataSource = new BasicDataSource();
            dbcpDataSource.setUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&amp;characterEncoding=utf8");
            dbcpDataSource.setDriverClassName("com.mysql.jdbc.Driver");
            dbcpDataSource.setUsername("root");
            dbcpDataSource.setPassword("123");
            dbcpDataSource.setDefaultAutoCommit(true);
            dbcpDataSource.setMaxActive(100);
            dbcpDataSource.setMaxIdle(30);
            dbcpDataSource.setMaxWait(500);
            DBHelper.dataSource = (DataSource)dbcpDataSource;
        }
        return new QueryRunner(DBHelper.dataSource);
    }
}

    

package com.yida.framework.lucene5.incrementindex;

import org.apache.lucene.analysis.Analyzer;

import proj.zoie.api.indexing.AbstractZoieIndexableInterpreter;
import proj.zoie.api.indexing.ZoieIndexable;

/**
 * 自定义Person-->Document的数据转换器的生产者
 * @author Lanxiaowei
 *
 */
public class CustomPersonZoieIndexableInterpreter extends AbstractZoieIndexableInterpreter<Person>{
	private Analyzer analyzer;
	
	@Override
	public ZoieIndexable convertAndInterpret(Person person) {
		return new PersonZoieIndexable(person, analyzer);
	}
	
	public CustomPersonZoieIndexableInterpreter() {}
	
	public CustomPersonZoieIndexableInterpreter(Analyzer analyzer) {
		super();
		this.analyzer = analyzer;
	}

	public Analyzer getAnalyzer() {
		return analyzer;
	}
	public void setAnalyzer(Analyzer analyzer) {
		this.analyzer = analyzer;
	}
}

   

package com.yida.framework.lucene5.incrementindex;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.IntField;
import org.apache.lucene.document.LongField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;

import proj.zoie.api.indexing.AbstractZoieIndexable;
/**
 * JavaBean与Document的转换器
 * @author Lanxiaowei
 *
 */
public class PersonZoieIndexable extends AbstractZoieIndexable {
	private Person person;
	private Analyzer analyzer;

	public PersonZoieIndexable(Person person) {
		super();
		this.person = person;
	}

	public PersonZoieIndexable(Person person, Analyzer analyzer) {
		super();
		this.person = person;
		this.analyzer = analyzer;
	}

	public Document buildDocument() {
		System.out.println("Person --> Document begining.");
		Document document = new Document();
		document.add(new Field("id",person.getId().toString(),Field.Store.YES,
			Field.Index.NOT_ANALYZED,Field.TermVector.NO));
		document.add(new StringField("personName", person.getPersonName(), Field.Store.YES));
		document.add(new StringField("sex", person.getSex(), Field.Store.YES));
		document.add(new LongField("birth", person.getBirth().getTime(), Field.Store.YES));
		document.add(new TextField("nativePlace", person.getNativePlace(), Field.Store.YES));
		document.add(new StringField("job", person.getJob(), Field.Store.YES));
		document.add(new IntField("salary", person.getSalary(), Field.Store.YES));
		document.add(new StringField("hobby", person.getHobby(), Field.Store.YES));
		document.add(new StringField("deleteFlag", person.isDeleteFlag() + "", Field.Store.YES));
		return document;
	}

	@Override
	public IndexingReq[] buildIndexingReqs() {
	    return new IndexingReq[] {new IndexingReq(buildDocument(), analyzer)};
	}

	@Override
	public long getUID() {
		return person.getId();
	}

	@Override
	public boolean isDeleted() {
		return person.isDeleteFlag();
	}
	
	public Analyzer getAnalyzer() {
		return analyzer;
	}

	public void setAnalyzer(Analyzer analyzer) {
		this.analyzer = analyzer;
	}
}

   

package com.yida.framework.lucene5.incrementindex;

import java.util.Date;

public class Person {
	private Long id;
	private String personName;
	/**性别:1(男)/0(女)*/
	private String sex;
	private Date birth;
	/**籍贯*/
	private String nativePlace;
	private String job;
	private Integer salary;
	/**兴趣爱好*/
	private String hobby;
	
	/**删除标记: true已删除/false未删除*/
	private boolean deleteFlag;
	/**最后一次更新时间*/
	private Date updatedTime;
	
	public Person() {}
	
	
	
	public Person(String personName, String sex, Date birth,
			String nativePlace, String job, Integer salary, String hobby) {
		super();
		this.personName = personName;
		this.sex = sex;
		this.birth = birth;
		this.nativePlace = nativePlace;
		this.job = job;
		this.salary = salary;
		this.hobby = hobby;
	}
	
	public Person(String personName, String sex, Date birth,
			String nativePlace, String job, Integer salary, String hobby,boolean deleteFlag) {
		super();
		this.personName = personName;
		this.sex = sex;
		this.birth = birth;
		this.nativePlace = nativePlace;
		this.job = job;
		this.salary = salary;
		this.hobby = hobby;
		this.deleteFlag = deleteFlag;
	}

	public Person(String personName, String sex, Date birth,
			String nativePlace, String job, Integer salary, String hobby,
			boolean deleteFlag, Date updatedTime) {
		super();
		this.personName = personName;
		this.sex = sex;
		this.birth = birth;
		this.nativePlace = nativePlace;
		this.job = job;
		this.salary = salary;
		this.hobby = hobby;
		this.deleteFlag = deleteFlag;
		this.updatedTime = updatedTime;
	}

	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	public String getPersonName() {
		return personName;
	}
	public void setPersonName(String personName) {
		this.personName = personName;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	public Date getBirth() {
		return birth;
	}
	public void setBirth(Date birth) {
		this.birth = birth;
	}
	public String getNativePlace() {
		return nativePlace;
	}
	public void setNativePlace(String nativePlace) {
		this.nativePlace = nativePlace;
	}
	public String getJob() {
		return job;
	}
	public void setJob(String job) {
		this.job = job;
	}
	public Integer getSalary() {
		return salary;
	}
	public void setSalary(Integer salary) {
		this.salary = salary;
	}
	public String getHobby() {
		return hobby;
	}
	public void setHobby(String hobby) {
		this.hobby = hobby;
	}

	public boolean isDeleteFlag() {
		return deleteFlag;
	}

	public void setDeleteFlag(boolean deleteFlag) {
		this.deleteFlag = deleteFlag;
	}

	public Date getUpdatedTime() {
		return updatedTime;
	}

	public void setUpdatedTime(Date updatedTime) {
		this.updatedTime = updatedTime;
	}



	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Person other = (Person) obj;
		if (id == null) {
			if (other.id != null)
				return false;
		} else if (!id.equals(other.id))
			return false;
		return true;
	}
}

   

package com.yida.framework.lucene5.incrementindex;

import java.util.List;

public interface PersonDao {
	/**
	 * 新增
	 * @return
	 */
	public boolean save(Person person);
	
	/**
	 * 更新
	 * @param person
	 * @return
	 */
	public boolean update(Person person);
	
	/**
	 * 根据ID删除
	 * @param id
	 * @return
	 */
	public boolean delete(Long id);
	
	/**
	 * 根据ID查询
	 * @param id
	 * @return
	 */
	public Person findById(Long id);
	
	/**
	 * 查询所有
	 * @return
	 */
	public List<Person> findAll();
	
	/**
	 * 查询3秒之前的数据,用于测试
	 * @return
	 */
	public List<Person> findPersonBefore3S();
}

   

package com.yida.framework.lucene5.incrementindex;

import java.sql.SQLException;
import java.util.Date;
import java.util.List;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;

public class PersonDaoImpl implements PersonDao {
	private QueryRunner queryRunner = DBHelper.getQueryRunner();
	/**
	 * 新增
	 * @return
	 */
	public boolean save(Person person) {
		int result = 0;
		try {
			result = queryRunner.update("insert into person(personName,sex,birth,nativePlace,job,salary,hobby,deleteFlag,updatedTime) " + 
					"values(?,?,?,?,?,?,?,?,?)" , new Object[] {
					person.getPersonName(),
					person.getSex(),
					person.getBirth(),
					person.getNativePlace(),
					person.getJob(),
					person.getSalary(),
					person.getHobby(),
					person.isDeleteFlag(),
					new Date()
			});
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return result == 1;
	}
	
	/**
	 * 根据ID更新
	 * @param person
	 * @return
	 */
	public boolean update(Person person) {
		int result = 0;
		try {
			result = queryRunner.update(
					"update person set personName = ?, sex = ?, birth = ?, " + 
					"nativePlace = ?, job = ?, salary = ?, hobby = ?,deleteFlag = ?, " +
					"updatedTime = ? where id = ?" 
					, new Object[] {
					person.getPersonName(),
					person.getSex(),
					person.getBirth(),
					person.getNativePlace(),
					person.getJob(),
					person.getSalary(),
					person.getHobby(),
					person.isDeleteFlag(),
					new Date(),
					person.getId()
			});
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return result == 1;
	}
	
	/**
	 * 根据ID删除
	 * @param id
	 * @return
	 */
	public boolean delete(Long id) {
		int result = 0;
		try {
			result = queryRunner.update("delete from person where id = ?", id);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return result == 1;
	}
	
	/**
	 * 根据ID查询
	 * @param id
	 * @return
	 */
	public Person findById(Long id) {
		Person person = null;
		try {
			person = queryRunner.query("select * from person where id = ?", new BeanHandler<Person>(Person.class),id);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return person;
	}
	
	/**
	 * 查询所有
	 * @return
	 */
	public List<Person> findAll() {
		List<Person> persons = null;
		try {
			persons = queryRunner.query("select * from person", new BeanListHandler<Person>(Person.class));
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return persons;
	}
	
	/**
	 * 查询3秒之前的数据,用于测试
	 * @return
	 */
	public List<Person> findPersonBefore3S() {
		List<Person> persons = null;
		try {
			persons = queryRunner.query("select * from person where updatedTime >= DATE_SUB(NOW(),INTERVAL 3 SECOND)", new BeanListHandler<Person>(Person.class));
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return persons;
	}
}

   

package com.yida.framework.lucene5.incrementindex;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * PersonDao测试
 * @author Lanxiaowei
 *
 */
public class PersonDaoTest {
	private static final DateFormat dateFormate = new SimpleDateFormat("yyyy-MM-dd");
	public static void main(String[] args) throws Exception {
		addPerson();
		
	}
	
	/**
	 * 添加一个Person测试
	 * @throws ParseException
	 */
	public static void addPerson() throws ParseException {
		PersonDao personDao = new PersonDaoImpl();
		String personName = "张国荣";
		String sex = "1";
		String birthString = "1956-09-12";
		Date birth = dateFormate.parse(birthString);
		String nativePlace = "中国香港九龙";
		String job = "歌手";
		Integer salary = 16000;
		String hobby = "演员&音乐";
		boolean deleteFlag = false;
		Person person = new Person(personName, sex, birth, nativePlace, job, salary, hobby, deleteFlag);
		boolean success = personDao.save(person);
		System.out.println(success ? "Person save successful." : "Person save fauilure.");
	}
}

   数据库建表SQL:

CREATE TABLE `person` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `personName` varchar(60) DEFAULT NULL,
  `sex` char(1) DEFAULT NULL,
  `birth` datetime DEFAULT NULL,
  `nativePlace` varchar(200) DEFAULT NULL,
  `job` varchar(60) DEFAULT NULL,
  `salary` int(11) DEFAULT NULL,
  `hobby` varchar(200) DEFAULT NULL,
  `deleteFlag` bit(1) DEFAULT NULL,
  `updatedTime` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;


INSERT INTO `person` VALUES (1, '兰小伟', '1', '1987-6-5 00:00:00', '湖北省武穴市', '码农', 16000, '看书写代码听歌看电影玩玩CS看看斯诺克比赛', '', '2015-4-6 18:01:30');
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,

或者加裙
一起交流学习!

  • 大小: 9 KB
  • 大小: 13.4 KB
  • 大小: 11 KB
1
0
分享到:
评论
5 楼 大树Kris 2016-05-25  
磁盘索引只读,删除文档如何处理呢?
4 楼 永志_爱戴 2016-04-03  
《这时就设计了一个内存索引目录B,即在内存索引目录A在往硬盘索引目录C中写索引的同时,也往内存索引目录B中写做个备份,这时使用Lucene中的MultiReader把B和C作为一个索引目录进行查询,之所以不包括A是因为A还没写完,》
博主的这句话感觉有些问题。
目录A在往硬盘索引目录写索引的时候,不应该是往索引目录B中写备份吧。往索引目录B里写的应该是要建的新的索引文档。而且使用IndexReaer进行索引时,应该不仅仅是返回B和C的索引目录,还要包括A的索引目录的Reader。


3 楼 wc149162536 2016-01-29  
有没有人用楼主的代码测试成功啊?  我是运行到ZoieIndex类 init方法 89 行 
zoieSystem = new ZoieSystem(idxDir, interpreter, readerDecorator, zoieConfig);
有错误,导致zoieSystem没有能被初始化,在线程里面报了空指针错误。我也是检查了好多地方没发觉错误,感觉是不是楼主的zoie-core  jar包没有没有修改准确呢? 大胆揣测,冒犯之处请多见谅
2 楼 jack40883 2015-05-03  
  确实,有部分包http://maven.oschina.net/上还没有...找起来麻烦版本还是个大问题..为了方便我们学习拜托了..别用maven吧...
1 楼 jack40883 2015-04-09  
麻烦大神下次能不用maven

相关推荐

Global site tag (gtag.js) - Google Analytics