<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>中文 &#187; foamflower</title>
	<atom:link href="http://software.intel.com/zh-cn/blogs/author/foamflower/feed/" rel="self" type="application/rss+xml" />
	<link>http://software.intel.com/zh-cn/blogs</link>
	<description></description>
	<lastBuildDate>Mon, 28 May 2012 13:40:23 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.3</generator>
		<item>
		<title>Lucene 多线程操作实现</title>
		<link>http://software.intel.com/zh-cn/blogs/2010/07/20/lucene/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2010/07/20/lucene/#comments</comments>
		<pubDate>Tue, 20 Jul 2010 01:16:13 +0000</pubDate>
		<dc:creator>foamflower</dc:creator>
				<category><![CDATA[博客征文专栏]]></category>
		<category><![CDATA[并行计算]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2010/07/20/lucene/</guid>
		<description><![CDATA[对于并发，Lucene 遵循以下规则： 1. 允许任意多的读操作并发，即任意数量用户可同时对同一索引做检索操作。 2. 即便正在进行索引修改操作(索引优化、添加文档、删除文档)，依然允许任意多的检索操作并发执行。 3. 不允许并发修改操作，也就是说同一时间只允许一个索引修改操作。 Lucene内部已经对多线程安全进行了处理，很多操作都使用了 lock 进行多线程同步锁定。只要遵循一定的规则，就可以在多线程环境下安全运行 Lucene。 方案一： 建议： 1. Directotry、Analyzer 都是多线程安全类型，只需建立一个 Singleton 对象即可。 2. 所有线程使用同一个 IndexModifier 对象进行索引修改操作。 3. IndexWriter/IndexReader/IndexModifier/IndexSearcher 最好使用同一个 Directory 对象，否则多线程并发读写时可能引发 FileNotFoundException。 IndexModifier 对象封装了 IndexWriter 和 IndexReader 的常用操作，其内部实现了多线程同步锁定。使用 IndexModifier 可避免同时使用 IndexWriter 和 IndexReader 时需要在多个对象之间进行同步的麻烦。等所有修改操作完成后，记住调用 Close() 方法关闭相关资源。并不是每次操作都需要调用 Optimize()，可以依据特定情况，定期执行优化操作。 -------- 以下演示代码简单封装了一个 IndexModifier Signleton 类型，确保多线程使用同一个对象，且只能由最后一个多线程调用 Close 方法关闭。 代码不完善，仅供参考！需要做些修改才能应用于实际项目。 //索引修改器的获取和关闭 import java.io.File; [...]]]></description>
			<content:encoded><![CDATA[<p>对于并发，Lucene 遵循以下规则：</p>
<p>1. 允许任意多的读操作并发，即任意数量用户可同时对同一索引做检索操作。<br />
2. 即便正在进行索引修改操作(索引优化、添加文档、删除文档)，依然允许任意多的检索操作并发执行。<br />
3. 不允许并发修改操作，也就是说同一时间只允许一个索引修改操作。</p>
<p>Lucene内部已经对多线程安全进行了处理，很多操作都使用了 lock 进行多线程同步锁定。只要遵循一定的规则，就可以在多线程环境下安全运行 Lucene。<br />
方案一：<br />
建议：</p>
<p>1. Directotry、Analyzer 都是多线程安全类型，只需建立一个 Singleton 对象即可。<br />
2. 所有线程使用同一个 IndexModifier 对象进行索引修改操作。<br />
3. IndexWriter/IndexReader/IndexModifier/IndexSearcher 最好使用同一个 Directory 对象，否则多线程并发读写时可能引发 FileNotFoundException。</p>
<p>IndexModifier 对象封装了 IndexWriter 和 IndexReader 的常用操作，其内部实现了多线程同步锁定。使用 IndexModifier 可避免同时使用 IndexWriter 和 IndexReader 时需要在多个对象之间进行同步的麻烦。等所有修改操作完成后，记住调用 Close() 方法关闭相关资源。并不是每次操作都需要调用 Optimize()，可以依据特定情况，定期执行优化操作。</p>
<p>--------</p>
<p>以下演示代码简单封装了一个 IndexModifier Signleton 类型，确保多线程使用同一个对象，且只能由最后一个多线程调用 Close 方法关闭。<br />
代码不完善，仅供参考！需要做些修改才能应用于实际项目。</p>
<p>//索引修改器的获取和关闭</p>
<p>import java.io.File;</p>
<p>import java.io.IOException;</p>
<p>import java.io.StringReader;</p>
<p>import java.util.ArrayList;</p>
<p>import java.util.HashMap;</p>
<p>import java.util.Map;</p>
<p>import org.apache.lucene.analysis.Analyzer;</p>
<p>import org.apache.lucene.analysis.standard.StandardAnalyzer;</p>
<p>import org.apache.lucene.index.CorruptIndexException;</p>
<p>import org.apache.lucene.index.IndexModifier;</p>
<p>import org.apache.lucene.store.Directory;</p>
<p>import org.apache.lucene.store.LockObtainFailedException;</p>
<p>import org.apache.lucene.store.RAMDirectory;</p>
<p>public class MyIndexModifier {</p>
<p>private static Analyzer analyzer = new StandardAnalyzer();</p>
<p>private static IndexModifier modifier;</p>
<p>private static ArrayList threadList = new ArrayList();</p>
<p>private MyIndexModifier() { }</p>
<p>static final File INDEX_DIR = new File("D:/docindex");</p>
<p>public static IndexModifier GetInstance()</p>
<p>{</p>
<p>synchronized (threadList)</p>
<p>{</p>
<p>if (modifier == null)</p>
<p>{</p>
<p>try {</p>
<p>modifier = new IndexModifier(INDEX_DIR, analyzer, false);</p>
<p>//索引性能测试参数配置</p>
<p>modifier.setMergeFactor(1000);</p>
<p>System.out.println("MergeFactor: " + modifier.getMergeFactor());</p>
<p>System.out.println("MaxBufferedDocs: " + modifier.getMaxBufferedDocs());</p>
<p>} catch (CorruptIndexException e) {</p>
<p>e.printStackTrace();</p>
<p>} catch (LockObtainFailedException e) {</p>
<p>e.printStackTrace();</p>
<p>} catch (IOException e) {</p>
<p>e.printStackTrace();</p>
<p>}</p>
<p>}</p>
<p>if (!threadList.contains(Thread.currentThread()))</p>
<p>threadList.add(Thread.currentThread());</p>
<p>return modifier;</p>
<p>}</p>
<p>}</p>
<p>public static void Close()</p>
<p>{</p>
<p>synchronized (threadList)</p>
<p>{</p>
<p>if (threadList.contains(Thread.currentThread()))</p>
<p>threadList.remove(Thread.currentThread());</p>
<p>if (threadList.size() == 0)</p>
<p>{</p>
<p>try {</p>
<p>if (modifier != null)</p>
<p>{</p>
<p>modifier.close();</p>
<p>modifier = null;</p>
<p>}</p>
<p>} catch (CorruptIndexException e) {</p>
<p>e.printStackTrace();</p>
<p>} catch (IOException e) {</p>
<p>e.printStackTrace();</p>
<p>}</p>
<p>}</p>
<p>}</p>
<p>}</p>
<p>}</p>
<p>//线程处理类</p>
<p>import java.io.IOException;</p>
<p>import java.util.Date;</p>
<p>import org.apache.log4j.LogManager;</p>
<p>import org.apache.log4j.Logger;</p>
<p>import org.apache.lucene.document.Document;</p>
<p>import org.apache.lucene.document.Field;</p>
<p>import org.apache.lucene.index.CorruptIndexException;</p>
<p>import org.apache.lucene.index.IndexModifier;</p>
<p>import org.apache.lucene.index.StaleReaderException;</p>
<p>import org.apache.lucene.store.LockObtainFailedException;</p>
<p>import com.miracle.dm.framework.common.TimestampConverter;</p>
<p>public class TestModifer extends Thread{</p>
<p>private static Logger logger = LogManager.getLogger(TestModifer.class);</p>
<p>@Override</p>
<p>public void run() {</p>
<p>IndexModifier writer = MyIndexModifier.GetInstance();</p>
<p>try {</p>
<p>writer.deleteDocument(0);</p>
<p>} catch (StaleReaderException e1) {</p>
<p>// TODO Auto-generated catch block</p>
<p>e1.printStackTrace();</p>
<p>} catch (CorruptIndexException e1) {</p>
<p>// TODO Auto-generated catch block</p>
<p>e1.printStackTrace();</p>
<p>} catch (LockObtainFailedException e1) {</p>
<p>// TODO Auto-generated catch block</p>
<p>e1.printStackTrace();</p>
<p>} catch (IOException e1) {</p>
<p>// TODO Auto-generated catch block</p>
<p>e1.printStackTrace();</p>
<p>}</p>
<p>for (int x = 0; x &lt; 10; x++)</p>
<p>{</p>
<p>Document doc = new Document();</p>
<p>TimestampConverter converter = new TimestampConverter();</p>
<p>Date date = new Date();</p>
<p>String docDate = converter.timestampToShortStr(date);</p>
<p>doc.add(new Field("docDate", docDate , Field.Store.YES, Field.Index.TOKENIZED));</p>
<p>try {</p>
<p>writer.addDocument(doc);</p>
<p>} catch (CorruptIndexException e) {</p>
<p>// TODO Auto-generated catch block</p>
<p>e.printStackTrace();</p>
<p>} catch (LockObtainFailedException e) {</p>
<p>// TODO Auto-generated catch block</p>
<p>e.printStackTrace();</p>
<p>} catch (IOException e) {</p>
<p>// TODO Auto-generated catch block</p>
<p>e.printStackTrace();</p>
<p>}</p>
<p>}</p>
<p>logger.debug(""+ Thread.currentThread()+","+ writer.docCount());</p>
<p>MyIndexModifier.Close(); // 注意不是调用 IndexModifier.Close() ！</p>
<p>}</p>
<p>}<br />
多线程测试代码</p>
<p>import java.io.Console;</p>
<p>import java.io.IOException;</p>
<p>import java.util.Date;</p>
<p>import org.apache.log4j.LogManager;</p>
<p>import org.apache.log4j.Logger;</p>
<p>import org.apache.lucene.document.Document;</p>
<p>import org.apache.lucene.document.Field;</p>
<p>import org.apache.lucene.index.CorruptIndexException;</p>
<p>import org.apache.lucene.index.IndexModifier;</p>
<p>import org.apache.lucene.store.LockObtainFailedException;</p>
<p>import com.miracle.dm.framework.common.TimestampConverter;</p>
<p>public class test {</p>
<p>private static Logger logger = LogManager.getLogger(test.class);</p>
<p>public test(){</p>
<p>}</p>
<p>/**</p>
<p>* @param args</p>
<p>*/</p>
<p>public static void main(String[] args) {</p>
<p>for (int i = 0; i &lt; 100; i++)</p>
<p>{</p>
<p>new TestModifer().start();</p>
<p>}</p>
<p>}</p>
<p>}</p>
<p>注意：使用lucene现在的新版本的朋友一定会发现，现在并不推荐使用。而查看API发现IndexModifier已经被IndexWriter代替。再查看IndexWriter，其中提供了新增，删除，更新索引文档的方法。</p>
<p>这里是自己编码来实现，但是我不知道当几千或更多用户在对索引进行操作，那会不会导致close长时间没有运行，而无法检索到最新的更新索引。希望大家帮我考虑一下是否会存在这方面的问题，如果存在该如何解决？</p>
<p>方案二：利用已有的lucene框架，例如compass</p>
<p>它对lucene实现了实时索引。可基于hibernate，当更新数据库时，系统会自动更新索引。</p>
<p>· Compass将lucene、Spring、Hibernate三者结合<br />
转自：http://wemyss.blogbus.com/logs/8014799.html</p>
<p>1.概述</p>
<p>Compass将lucene、Spring、Hibernate三者的起来，以很低很低的成本快速实现企业应用中的搜索功能。</p>
<p>HomePage: http://www.opensymphony.com/compass/</p>
<p>springside里用了compass来做图书搜索，快速建立的流程如下：</p>
<p>1.用简单的compass annotation把Book对象映射到Lucene。</p>
<p>2.配置compass默认提供的基于Spring MVC的Index Controller 和Search Controller。</p>
<p>3.编写查询结果的显示页面，将controller返回的变量显示出来。</p>
<p>2.Object/Search Engine Mapping的 Annotations配置</p>
<p>使用JDK5 的annotation 来进行OSEM(Object/Search Engine Mapping)比用xml文件按简单许多，下面就是简单的搜索类，可见@SearchableID, @SearchableProperty与@SearchableComponent 三个标记，分别代表主键、可搜索的属性与关联的，另一个可搜索的对象，另外Compass要求POJO要有默认构造函数，要实现equals()和hashcode():</p>
<p>详细请点击查看springside中的Product.java , Book.java, Category.java<br />
<img src="http://images.csdn.net/upimgs/liyp/02.png" alt="" /><br />
3. 与spring,hibernate集成配置</p>
<p>3.1 spring配置文件</p>
<p>hiberante中的sessionFactory,transactionManager相比大家也是轻车熟路了.这里还是带过(因为不牵扯稿费的问题吗^_^ ).compass已经对对spring集成做了很好的封装，让我们的使用更加简单,我们可以不为compass编写一行代码,就可以做完搜索引擎的检索.下面是compass在spring中的简明配置. 详情点击查看springside中的applicationContext-lucene.xml ：<br />
<img src="http://images.csdn.net/upimgs/liyp/03.png" alt="" /><br />
上面要留意的配置有：</p>
<p>annotationConfiguration: 使用annotation配置，指定要转换的POJO如Book<br />
compass.engine.connection : 索引文件在服务器上的存储路径.<br />
hibernateGpsDevice: 与hibernate的绑定，用Hibernate 3 事件系统,支持Real Time Data Mirroring .经Hiberante的数据改变会自动被反射到索引里面.</p>
<p>3.2 web Controller的配置</p>
<p>两个Controller都是现成的，只要配置相关选项即可。</p>
<p>详情请查看springside的bookstore-servlet.xml<br />
<img src="http://images.csdn.net/upimgs/liyp/04.png" alt="" /><br />
3.3 View JSP</p>
<p>简单搜索页面:只需要一个query 参数:</p>
<p>结果页面:</p>
<p>结果页面将返回几个变量，包括:</p>
<p>searchResults(搜索结果) 包括hits(结果)和 searchtime(耗时)<br />
pages(分页信息) 包括page_from page_to等<br />
command(原来的查询请求)</p>
<p>具体使用见springside的advancedSearch.jsp ,下面是简版的代码:<br />
<img src="http://images.csdn.net/upimgs/liyp/05.png" alt="" /><br />
4.扩展高级搜索</p>
<p>扩展高级搜索其实很简单,SpringSide已经初步封装了加入包含以下任意单词，不包含以下任何单词，分类选择等条件及每页显示条数的确定。</p>
<p>如果需要更多条件：</p>
<p>1. 加强搜索页面，加入更多条件的显示。</p>
<p>2. 扩展compass的command class，接受从搜索条件页传过来的条件。 可从springside的AdvancedSearchCommand 扩展或从Compass的原类扩展。</p>
<p>3. 扩展compass的searchController, 将command中的变量重新处理为一个符合Lucene语法规则的query变量 即可(见springside中的AdvancedSearchController )，同时可以为搜索条件页查询图书分类列表一类的变量。</p>
<p>你可以从springside的AdvancedSearchController扩展，重载onSetupCommand (),参考父类的做法，加装自己的条件。重载referenceData()，把图书分类列表这种条件加入到AdvancedSearchCommand 的referenceData Map中供搜索条件页显示，例子见BookSearchController。</p>
<p>也可以参考BookSearchController和AdvancedSearchController的做法，完全自行扩展。</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2010/07/20/lucene/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

