lucene 并发4.7 50线程并发查询,怎么提升效率

总结:如何使用redis缓存加索引处理数据库百万级并发 - 推酷
总结:如何使用redis缓存加索引处理数据库百万级并发
前言:事先说明:在实际应用中这种做法设计需要各位读者自己设计,本文只提供一种思想。准备工作:安装后本地数redis服务器,使用mysql数据库,事先插入1000万条数据,可以参考我之前的文章插入数据,这里不再细说。我大概的做法是这样的,编码使用多线程访问我的数据库,在访问数据库前先访问redis缓存没有的话在去查询数据库,需要注意的是redis最大连接数最好设置为300,不然会出现很多报错。
贴一下代码吧
import redis.clients.jedis.JedisP
import redis.clients.jedis.JedisPoolC
public class SelectFromMysql {
public static void main(String[] args) {
JedisPoolConfig config = new JedisPoolConfig();//创建redis连接池
// 设置最大连接数,-1无限制
config.setMaxTotal(300);
// 设置最大空闲连接
config.setMaxIdle(100);
// 设置最大阻塞时间,记住是毫秒数milliseconds
config.setMaxWaitMillis(100000);
// 创建连接池
pool = new JedisPool(config, &127.0.0.1&, );
for (int i =9222000; i &=9222200; i++) {//这里自己设置用多少线程并发访问
String teacherName=String.valueOf(i);
new ThreadToMysql(teacherName, &123456&,pool).start();
import java.sql.C
import java.sql.DriverM
import java.sql.ResultS
import java.sql.SQLE
import java.sql.S
import redis.clients.jedis.J
import redis.clients.jedis.JedisP
public class ThreadToMysql extends Thread {
public String teacherN
public JedisP
public ThreadToMysql(String teacherName, String password,JedisPool pool) {//构造函数传入要查询登录的老师姓名和密码
this.teacherName=teacherN
this.password=
this.pool=
public void run() {
Jedis jedis = pool.getResource();
Long startTime=System.currentTimeMillis();//开始时间
if (jedis.get(teacherName)!=null) {
Long entTime=System.currentTimeMillis();//开始时间
System.out.println(currentThread().getName()+& 缓存得到的结果: &+jedis.get(teacherName)+& 开始时间:&+startTime+&
结束时间:&+entTime+&
用时:& +(entTime-startTime)+&ms&);
pool.returnResource(jedis);
System.out.println(&释放该redis连接&);
String url = &jdbc:mysql://127.0.0.1/teacher&;
String name = &com.mysql.jdbc.Driver&;
String user = &root&;
String password = &123456&;
Connection conn =
Class.forName(name);
conn = DriverManager.getConnection(url, user, password);//获取连接
conn.setAutoCommit(false);//关闭自动提交,不然mit()运行到这句会报错
} catch (ClassNotFoundException e1) {
e1.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
if (conn!=null) {
String sql=&select t_name from test_teacher where t_name='&+teacherName+&' and t_password='&+password+&' &;//SQL语句
String t_name=
Statement stmt=conn.createStatement();
ResultSet rs=stmt.executeQuery(sql);//获取结果集
if (rs.next()) {
t_name=rs.getString(&t_name&);
jedis.set(teacherName, t_name);
System.out.println(&释放该连接&);
stmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}finally {
pool.returnResource(jedis);
System.out.println(&释放该连接&);
Long end=System.currentTimeMillis();
System.out.println(currentThread().getName()+&
数据库得到的查询结果:&+t_name+&
开始时间:&+startTime+&
结束时间:&+end+&
用时:&+(end-startTime)+&ms&);
System.out.println(currentThread().getName()+&数据库连接失败:&);
我的数据库表数据是这样的。可以看到我的t_name是1-,密码固定123456.利用循环创建线程很好做传入循环的次数作为查询的t_name就行了
采用redis 缓存替换加索引的方案
1. 在200 并发访问下:
第一次访问结果:由于第一次访问缓存不存在该数据,速度很慢
最慢90多秒
运行第二次访问后(redis数据库已存在数据)的结果:
最慢700多毫秒
2. 当我尝试1000 线程并发访问时redis 直接挂掉,原因在于reids 缓存并没有要查找的数据, 就从数据库查找,1000 个线程同时并发访问数据库等待时间太长了,造成redis 连接等待超时( 就算把redis 的超时等待时间设置为100 分钟也没用,会报redis 连接被拒绝的错误)
3.当我利用循环事先把100万条数据插入redis缓存服务器后,在1万个线程并发访问测试下只需要5~6秒就拿到了查询结果,效率出奇的快,而且没有报任何错
4.在3的条件下我把并发线程提升到100万个时,测试在百万并发条件下查询性能,发现完全没有压力,每个线程也是几毫秒就能查到结果,这个时候限制我速度的就是电脑CPU了。我的测试电脑是4核的,处理100万个线程起来比较慢,下面是截图,运行到50多万个线程的时候我就停止了运行
好了,以上都是数据库查询的字段没有加索引直接利用redis缓存查找的
而且有个弊端,百万级的并发访问需要事先把数据放到缓存中,在实际中并不科学(因为并不知道那些是热点数据),下面来看看如何使用索引加缓存的效果
1.给t_name和t_password字段加组合索引
我们来看看在有索引且redis缓存事先没有数据的时候,创建100万个线程并发访问的结果
没问题,这样就完成了百万级别下的并发访问,但是这样我的程序创建线程很慢,因为我的电脑4核CPU的(但是要创建100万个线程),这个时候就是硬件设备的性能了,在设备硬件性能足够的条件下是没问题的
以下是我的总结:
1.我的优化方案中只有两种,一种是给查询的字段加组合索引。另一种是给在用户和数据库中增加缓存
2.添加索引方案:面对1~2千的并发是没有压力的,在往上则限制的瓶颈就是数据库最大连接数了,在上面中我用show global status like 'Max_used_connections’查看数据库可以知道数据库最大响应连接数是5700多,超过这个数tomcat直接报错连接被拒绝或者连接已经失效
3.缓存方案:在上面的测试可以知道,要是我们事先把数据库的千万条数据同步到redis缓存中,瓶颈就是我们的设备硬件性能了,假如我们的主机有几百个核心CPU,就算是千万级的并发下也可以完全无压力,带个用户很好的。
4.索引+缓存方案:缓存事先没有要查询的数据,在一万的并发下测试数据库毫无压力,程序先通过查缓存再查数据库大大减轻了数据库的压力,即使缓存不命中在一万的并发下也能正常访问,在10万并发下数据库依然没压力,但是redis服务器设置最大连接数300去处理10万的线程,4核CPU处理不过来,很多redis连接不了。我用show global status like 'Max_used_connections'查看数据库发现最大响应连接数是388,这么低所以数据库是不会挂掉的。
5.使用场景:a.几百或者2000以下并发直接加上组合索引就可以了。b.不想加索引又高并发的情况下可以先事先把数据放到缓存中,硬件设备支持下可解决百万级并发。c.加索引且缓存事先没有数据,在硬件设备支持下可解决百万级并发问题。d.不加索引且缓存事先没有数据,不可取,要80多秒才能得到结果,用户体验极差。
6.原理:其实使用了redis的话为什么数据库不会崩溃是因为redis最大连接数为300,这样数据库最大同时连接数也是300多,所以不会挂掉,至于redis为什么设置为300是因为设置的太高就会报错(连接被拒绝)或者等待超时(就算设置等待超时的时间很长也会报这个错)。
最后说明:本文不代表实际应用开发场景,更多的是提供一种思想,一种解决方案,如有错误,请指正,谢谢
技术交流群:
本文源码:
本代码需要的jar包下载地址:
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致如何提高lucene的效率_百度知道1502人阅读
Lucene(1)
创建IndexWriter的方式:public class HelloWorld_2 {
public void createIndex() throws Exception {
Directory directory = FSDirectory.open(new File(&./indexDir/&));
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_36);
IndexWriterConfig indexWriterConfig = new
IndexWriterConfig(Version.LUCENE_36,analyzer);
IndexWriter indexWriter = new IndexWriter(directory,indexWriterConfig);
在Lucene程序中,成功以上面的方式创建IndexWriter对象以后,会在索引库中出现一个锁文件,这个锁文件是当前这个IndexWriter的锁,如果调用indexWriter.close()关闭了链接,则将会把这个锁文件删除,也就是说,它释放了锁。释放以后,第二个IndexWriter再开启是没有问题的。如果不关闭,同时开了两个或以上的IndexWriter,会抛出一个异常。导致程序终止。
解决方案就是:通过某种方法保证IndexWriter对象只创建一个。
出现的锁文件:
当调用IndexWriter的close方法后,这个锁文件就消失了。
1,多线程并发问题模拟
下面程序开启了两个IndexWriter,都没有关闭,执行结果抛出异常:
org.apache.lucene.store.LockObtainFailedException:Lock obtain timed out:NativeFSLock@D:\itcast2\lucene\indexDir\write.lock
public class MultiThreadTest {
public void test() throws Exception {
//创建索引配置。
IndexWriterConfig indexWriterConfig1 = new IndexWriterConfig(Version.LUCENE_36, DirAnaUtil.getAnalyzer());
IndexWriter indexWriter1 = new IndexWriter(DirAnaUtil.getDirectory(), indexWriterConfig1);
indexWriter1.close();
//创建第二个,模拟并发问题。
IndexWriterConfig indexWriterConfig2 = new IndexWriterConfig(Version.LUCENE_36, DirAnaUtil.getAnalyzer());
IndexWriter indexWriter2 = new IndexWriter(DirAnaUtil.getDirectory(), indexWriterConfig2);
indexWriter2.close();
造成错误的原因是:indexWriter1创建成功后,持有一个锁,这时还没有关闭indexWriter1,indexWriter2也要来拿这个锁,而现在这个锁被indexWriter1持有,indexWriter2无法获取,所以异常。
只要两次使用同一个对象就可以保证没有并发问题了。这里通过一个工具类来提供一个全局唯一的IndexWriter对象。如下:
* 获取唯一的IndexWriter对象
* 原理:通过静态代码块static{}在类的生命周期中只加载一次的特点,完成唯一的对象的创建
* @author 许智敏
public class LuceneUtils {
private static IndexWriter indexW
IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_36, DirAnaUtil.getAnalyzer());
indexWriter = new IndexWriter(DirAnaUtil.getDirectory(), indexWriterConfig);
} catch (Exception e) {
e.printStackTrace();
/**当当前线程结束时,自动关闭IndexWriter,使用Runtime对象*/
Runtime.getRuntime().addShutdownHook(new Thread(){
public void run() {
closeIndexWriter();
} catch (Exception e) {
e.printStackTrace();
/**在线程结束时,自动关闭IndexWriter*/
public static IndexWriter getIndexWriter() {
return indexW
/**关闭IndexWriter
* @throws IOException
* @throws CorruptIndexException */
public static void closeIndexWriter() throws Exception {
if(indexWriter != null) {
indexWriter.close();
然后我们通过这个工具类获取IndexWriter对象,就没有问题了。
public class MultiThreadTest {
public void test() throws Exception {
IndexWriter indexWriter1 = LuceneUtils.getIndexWriter();
System.out.println(indexWriter1);
IndexWriter indexWriter2 = LuceneUtils.getIndexWriter();
System.out.println(indexWriter2);
可在控制台看到,这两个对象是一样的。
至于IndexSearcher,它是从索引库中获取数据的,不涉及对索引库中内容的增删改,所以IndexSearcher没有并发问题。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:135499次
积分:2785
积分:2785
排名:第9440名
原创:145篇
评论:16条
(3)(8)(16)(122)(KnightLiao)
第三方登录:& & 目前线上solr每个replica索引2G左右,每次重新启动需要10分钟,无法忍受。
& & 观察solr的日志,发现打印红色部分前后用去了5分钟,前一条log“registering core”很具迷惑性,以为是注册core时耗费的时间,后来发现这个注册core和初始化SolrCore时的创建searcher不是同一个线程。真正耗费时间的时创建新的searcher的时候。
[ 16:45:07.624]11714 [searcherExecutor-8-thread-1] INFO
org.apache.solr.core.SolrCore
[autocplt] Registered new searcher Searcher@5feed5f2[autocplt] main{StandardDirectoryReader(segments_2cf:52943:nrt _e2o(4.7):C34398/51:delGen=1 _e2n(4.7):C14/1:delGen=1 _e2p(4.7):C16/5:delGen=2 _e2q(4.7):C9 _e2r(4.7):C29/6:delGen=1)}
[ 16:45:07.627]11717 [coreLoadExecutor-4-thread-4] WARN
org.apache.solr.core.SolrCore
WARNING: RealTimeGetHandler is not registered at /get. SolrCloud will always use full index replication instead of the more efficient PeerSync method.
[ 16:45:07.628]11717 [coreLoadExecutor-4-thread-4] INFO
org.apache.solr.core.CoreContainer
registering core: autocplt
&span style=&color:#ff0000;&&[ 16:50:11.020]315109 [searcherExecutor-7-thread-1] INFO
org.apache.solr.core.SolrCore
[doc] Registered new searcher Searcher@b4914ab[doc] main{StandardDirectoryReader(segments_475:73489:nrt _jey(4.7):C0186:delGen=333 _ize(4.7):C87432/7:delGen=4 _juk(4.7):C:delGen=18 _k0o(4.7):C:delGen=8 _ji1(4.7):C:delGen=6 _jnu(4.7):C:delGen=50 _jkt(4.7):C:delGen=68 _jgn(4.7):C29798/43:delGen=4 _jxm(4.7):C:delGen=2 _jr7(4.7):C:delGen=32 _jw8(4.7):C77157/7:delGen=4 _k18(4.7):C32746 _kv7(4.7):C39331/17:delGen=13 _k1r(4.7):C39768/10:delGen=5 _k1i(4.7):C35555/6:delGen=3 _k2l(4.7):C20458 _k22(4.7):C45921/2:delGen=2 _k2b(4.7):C48949/13:delGen=3 _kya(4.7):C664/1:delGen=1 _kyk(4.7):C710/1:delGen=1 _kyl(4.7):C6 _kym(4.7):C14 _kyn(4.7):C6 _kyo(4.7):C1 _kyp(4.7):C6 _kyq(4.7):C4 _kyr(4.7):C1 _kys(4.7):C9)}&/span&
[ 16:50:11.026]315115 [coreLoadExecutor-4-thread-1] WARN
org.apache.solr.core.SolrCore
WARNING: RealTimeGetHandler is not registered at /get. SolrCloud will always use full index replication instead of the more efficient PeerSync method.
[ 16:50:11.026]315116 [coreLoadExecutor-4-thread-1] INFO
org.apache.solr.core.CoreContainer
registering core: doc
[ 16:50:11.111]315200 [coreZkRegister-1-thread-1] INFO
org.apache.solr.cloud.ZkController
Register replica - core:editor address:http://XXX/solr collection:editorCollection shard:shard2
[ 16:50:11.111]315201 [coreZkRegister-1-thread-3] INFO
org.apache.solr.cloud.ZkController
Register replica - core:autocplt address:http://XXX/solr collection:autocpltCollection shard:shard2
[ 16:50:11.112]315201 [coreZkRegister-1-thread-4] INFO
org.apache.solr.cloud.ZkController
Register replica - core:doc address:http://XXX/solr collection:docCollection shard:shard2
[ 16:50:11.113]315200 [coreZkRegister-1-thread-2] INFO
org.apache.solr.cloud.ZkController
Register replica - core:cgindex address:http://XXX/solr collection:cgindexCollection shard:shard2
用jstack看了线程执行状况:
&searcherExecutor-8-thread-1& prio=10 tid=0x3800 nid=0x79e5 runnable [0x00007fd69bff0000]
java.lang.Thread.State: RUNNABLE
at java.nio.Bits.copyToByteArray(Native Method)
at java.nio.DirectByteBuffer.get(DirectByteBuffer.java:224)
at org.apache.lucene.store.ByteBufferIndexInput.readBytes(ByteBufferIndexInput.java:92)
at org.apache.pressing.LZ4.decompress(LZ4.java:101)
at org.apache.pressionMode$4.decompress(CompressionMode.java:135)
at org.apache.pressingStoredFieldsReader.visitDocument(CompressingStoredFieldsReader.java:336)
at org.apache.lucene.index.SegmentReader.document(SegmentReader.java:279)
at org.apache.lucene.index.BaseCompositeReader.document(BaseCompositeReader.java:110)
at org.apache.lucene.index.IndexReader.document(IndexReader.java:457)
at org.apache.lucene.search.suggest.DocumentDictionary$DocumentInputIterator.next(DocumentDictionary.java:138)
at org.apache.lucene.search.suggest.analyzing.AnalyzingSuggester.build(AnalyzingSuggester.java:402)
at org.apache.lucene.search.suggest.Lookup.build(Lookup.java:165)
at org.apache.solr.spelling.suggest.SolrSuggester.build(SolrSuggester.java:142)
at org.apache.solr.spelling.suggest.SolrSuggester.reload(SolrSuggester.java:169)
at org.apache.ponent.SuggestComponent$SuggesterListener.newSearcher(SuggestComponent.java:465)
at org.apache.solr.core.SolrCore$5.call(SolrCore.java:1695)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)
Locked ownable synchronizers:
- &0x00007fddf7093888& (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
&coreLoadExecutor-4-thread-4& prio=10 tid=0x0f6000 nid=0x79e1 in Object.wait() [0x00007fd79bff4000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on &0x00007fddf4b15e60& (a java.lang.Object)
at java.lang.Object.wait(Object.java:485)
at org.apache.solr.core.SolrCore.getSearcher(SolrCore.java:1590)
- locked &0x00007fddf4b15e60& (a java.lang.Object)
at org.apache.solr.core.SolrCore.getSearcher(SolrCore.java:1390)
at org.apache.solr.core.SolrCore.getSearcher(SolrCore.java:1325)
at org.apache.solr.handler.ReplicationHandler.getIndexVersion(ReplicationHandler.java:547)
at org.apache.solr.handler.ReplicationHandler.getStatistics(ReplicationHandler.java:564)
at org.apache.solr.core.JmxMonitoredMap$SolrDynamicMBean.getMBeanInfo(JmxMonitoredMap.java:236)
at com.caucho.jmx.MBeanWrapper.getMBeanInfo(MBeanWrapper.java:160)
at com.caucho.jmx.MBeanContext.getDebugName(MBeanContext.java:588)
at com.caucho.jmx.MBeanContext.addMBean(MBeanContext.java:364)
at com.caucho.jmx.MBeanContext.registerMBean(MBeanContext.java:251)
at com.caucho.jmx.AbstractMBeanServer.registerMBean(AbstractMBeanServer.java:440)
at org.apache.solr.core.JmxMonitoredMap.put(JmxMonitoredMap.java:140)
at org.apache.solr.core.JmxMonitoredMap.put(JmxMonitoredMap.java:51)
at org.apache.solr.rm(SolrResourceLoader.java:677)
at org.apache.solr.core.SolrCore.&init&(SolrCore.java:859)
at org.apache.solr.core.SolrCore.&init&(SolrCore.java:630)
at org.apache.solr.core.ZkContainer.createFromZk(ZkContainer.java:245)
at org.apache.solr.core.CoreContainer.create(CoreContainer.java:595)
at org.apache.solr.core.CoreContainer$1.call(CoreContainer.java:258)
at org.apache.solr.core.CoreContainer$1.call(CoreContainer.java:250)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)
Locked ownable synchronizers:
- &0x00007fdf0b089748& (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
&main& prio=10 tid=0xd800 nid=0x79b9 waiting on condition [0x00007feaadd32000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for
&0x00007fdf09bee000& (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:158)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1925)
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:399)
at java.util.concurrent.ExecutorCompletionService.take(ExecutorCompletionService.java:164)
at org.apache.solr.core.CoreContainer.load(CoreContainer.java:293)
at org.apache.solr.servlet.SolrDispatchFilter.createCoreContainer(SolrDispatchFilter.java:187)
at org.apache.solr.servlet.SolrDispatchFilter.init(SolrDispatchFilter.java:134)
at com.caucho.server.dispatch.FilterManager.createFilter(FilterManager.java:134)
- locked &0x00007fdf09bee2d0& (a com.caucho.server.dispatch.FilterConfigImpl)
at com.caucho.server.dispatch.FilterManager.init(FilterManager.java:87)
at com.caucho.server.webapp.Application.start(Application.java:1655)
at com.caucho.server.deploy.DeployController.startImpl(DeployController.java:621)
at com.caucho.server.deploy.StartAutoRedeployAutoStrategy.startOnInit(StartAutoRedeployAutoStrategy.java:72)
at com.caucho.server.deploy.DeployController.startOnInit(DeployController.java:509)
at com.caucho.server.deploy.DeployContainer.start(DeployContainer.java:153)
at com.caucho.server.webapp.ApplicationContainer.start(ApplicationContainer.java:670)
at com.caucho.server.host.Host.start(Host.java:420)
at com.caucho.server.deploy.DeployController.startImpl(DeployController.java:621)
at com.caucho.server.deploy.StartAutoRedeployAutoStrategy.startOnInit(StartAutoRedeployAutoStrategy.java:72)
at com.caucho.server.deploy.DeployController.startOnInit(DeployController.java:509)
at com.caucho.server.deploy.DeployContainer.start(DeployContainer.java:153)
at com.caucho.server.host.HostContainer.start(HostContainer.java:504)
at com.caucho.server.resin.ServletServer.start(ServletServer.java:971)
at com.caucho.server.deploy.DeployController.startImpl(DeployController.java:621)
at com.caucho.server.deploy.AbstractDeployControllerStrategy.start(AbstractDeployControllerStrategy.java:56)
at com.caucho.server.deploy.DeployController.start(DeployController.java:517)
at com.caucho.server.resin.ResinServer.start(ResinServer.java:551)
at com.caucho.server.resin.Resin.init(Resin.java)
at com.caucho.server.resin.Resin.main(Resin.java:625)
Locked ownable synchronizers:
可见main中是停在了Future&SolrCore& future = completionService.take();等待线程执行完成,coreLoadExecutor-4-thread-4是停在了searcherLock.wait();
等待被唤醒,而searcherExecutor-8-thread-1一直在读文件,并且是component.SuggestComponent在操作,由于solrconfig.xml里配置了suggest,但是suggest功能单独做了拼音索引,没有使用solr的这个suggest功能,去掉了solrconfig.xml中得相关配置,启动时间由10分钟变为了10s。
solr提供的suggest功能由线程栈大概可以看出都做了哪些操作,还进行了压缩,有时间时仔细看看源码。
转自:http://blog.csdn.net/wenchanter/article/details/
如非特别注明,本站内容均为原创,转载请务必注明作者和原始出处。
本文地址:
Solr采用Lucene搜索库为核心,提供全文索引和搜索开源企业平台,提供REST的HTTP/XML和JSON的API。
大家都在看

我要回帖

更多关于 lucene 4.7 的文章

 

随机推荐