Solr入门和实践以及我对Solr的8点理解
友情提示
Solr的内容还是比较多的,一篇文章只能讲解一部分。
全面介绍,没兴趣,没时间,也没能力,回报还不大。
本文只写点我认为比较重要的知识点,独特的个人想法。
仅供参考哦,更多细节需要自己去琢磨。
概述
Solr是一个高性能,采用Java5开发,基于Lucene的全文搜索服务器。同时对其进行了扩展,提供了比Lucene更为丰富的查询语言,
同时实现了可配置、可扩展并对查询性能进行了优化,并且提供了一个完善的功能管理界面,是一款非常优秀的全文搜索引擎。
工作方式
文档通过Http利用XML 加到一个搜索集合中。
查询该集合也是通过http收到一个XML/JSON响应来实现。
它的主要特性包括:高效、灵活的缓存功能,垂直搜索功能,高亮显示搜索结果,通过索引复制来提高可用性,
提供一套强大Data Schema来定义字段,类型和设置文本分析,提供基于Web的管理界面等。
需求场景
查询和搜索,我们直接查询数据库MySQL。查询数据库主要有一些局限性:
比如多表查询效率低,大文本字段不好建立索引和搜索,复杂的条件查询和搜索功能不够强大,或者说不够简单。
使用Solr的话,就很简单地解决了以上问题。
以上需求,或者说关系型数据库mysql的问题,只是目前的一点理解。
虽说能够使用MySQL和Sorl解决实际中的问题,但毕竟都是中低难度的问题(自认为如此哦)。
非要说深入理解,剖析Solr的好处,MySQL是否“干的过”Solr,真心不懂。
单独搞MySQL,够你研究5年以上,DBA毕竟是个传说。
Solr,想搞懂,也得好多年。
个人同时学习Java服务端、Android、iOS、Web前端,目标是能够解决工作中最常见的问题,并不想要
深入学习有限的几种技术,比如MySQL,达到那种“再难的问题,也可以搞定”的程度。
我对Solr的8点理解
1.定义数据源接口,获得数据。
比如定义MySQL查询语句,把一个表或多个表的数据,导入到Solr中。
这个地方我觉得特别“不公平”,数据都是从别的地方搞过来的。外界的数据如果会变化,意味着,必须处理“数据同步”。
实时性要求不高的情况下,可以每天“全量更新”。要求高的情况下,单条数据的变化,需要“实时更新-单条”。
因此,Solr和Mysql并不是“直接竞争”关系,而是“互补”的关系。
2.把Mysql等数据源的数据,导入到Solr中去。
Solr定义数据,可以理解成一张很大的表,包含了很多字段,比如可以包含mysql中3个表的所有字段。
这样,查询就不存在“多表”的问题。
既然是一张表,建立索引,查询就很快了。
3.自带缓存功能。
Mysql,Solr,Redis等数据源或者有能力获得数据和管理数据的组件,只要需要,就可以提供“缓存”功能。
Solr简化了查询,缓存就更容易了。
4.索引和全文搜索。
Solr底层采用Lucene建立索引,全文索引,这样可以实现更多的“搜索功能”,可以说增强了Mysql的查询。
5.站内搜索的另外一种形式。
百度等搜索引擎,可以为网站提供“站内搜索”功能,他们爬去数据可以是公开的URL的形式。
如果需要和百度等合作,可以申请使用百度的搜索API,将站内数据,更友好,更快速地告诉百度。
而Solr和百度提供的搜索相关接口就基本一样,只不过是处在我们的管理之下。
6.简洁使用的管理界面。
后台有Web界面,导入数据,更新,可以通过可视化的操作来管理,比较方便。
7.功能服务化。
Solr提供的查询等功能,有Java等多种语言的实现。
建立数据结构,导入数据,维护缓存和实时性,最重要的就是“查询”和“搜索”了。
8.最大的“隐患”。
只用Mysql管理数据和查询的时候,我们必须并且只需要保障mysql的“高可用性”。
不能出任何问题,如果只用1个Mysql,意味着我们需要实时监控Mysql是否可用,如果出了问题,我们需要立即修复它。
如果是多台Mysql,我们需要用主从,或者更复杂的主从。
现在用了Solr,意味着,我们很多查询和搜索,优先使用Solr,不再使用Mysql。
这个时候,为了“高可靠性”,我们也必须保障Solr是靠谱的。
单台Solr服务器,可靠性怎么样,我不太清楚。
无论单台Solr是否靠谱,多台Solr更加靠谱,这都意味着
“我们程序中必须可靠的基础服务更多了”。
常见的必须“高可用性”的服务有
a.Mysql
b.Redis
3.Nginx
4.Solr
高可用性的服务越多,意味着我们的程序越复杂。
大部分的公司,都是中小型企业。
大部分的应用,都是为了快速推出,看看是否有效果。
真正需要保障“高可靠性”的项目,是很少的,如果遇到了,是很幸运的。
官方网站:http://lucene.apache.org/solr/
本地环境:Windows-5.3.1版本
运行和建立工程
启动:solr.cmd start(类似这样)
建立工程:
name=raikou
config=solrconfig.xml
schema=schema.xml
dataDir=J:\SoftData\Solr\raikou\data
指定config、schema等多种参数。
(图文并茂的入门指引,可以参考其它博主的文章,本人觉得这种“图文并茂”的太尼玛费事了。
方便了读者,但是“技术含量”不够高,博主表示不过瘾o(︶︿︶)o )
简要介绍下几个配置,附带源文件内容
core.properties
1
2
3
4
|
name=raikou(项目名称) config=solrconfig.xml(Solr配置) schema=schema.xml(模式定义) dataDir=J:\SoftData\Solr\raikou\data (存储索引等数据) |
Web界面输入的内容,保存在这了,入口配置,可以这么说。
schema.xml
1
2
3
4
|
<field indexed= "true" multivalued= "false" name= "id" required= "true" stored= "true" type= "long" > <field indexed= "true" name= "title" required= "true" stored= "true" type= "string" > <field indexed= "true" name= "content" stored= "true" type= "string" > <field indexed= "true" name= "summary" stored= "true" type= "string" > </field></field></field></field> |
定义了几个字段
id
title
唯一字段,默认查询字段
schemal.xml还配置了若干其它配置文件,比如“stopwords_en.txt”、“protwords.txt”、“stopwords.txt”等。
如果Solr启动报错,可能是缺少了这些字段。
data-config.xml
1
2
3
4
5
6
7
8
9
|
<!--?xml version= 1.0 encoding=UTF- 8 ?--> <dataconfig> <datasource driver= "com.mysql.jdbc.Driver" password= "mypassword/" type= "JdbcDataSource" url= "jdbc:mysql://localhost:3306/raikou?useUnicode=true&characterEncoding=UTF-8" user= "root" > <document name= "raikou_article" > <entity deltaimportquery= "select" deltaquery= "select" from= "" id= "${dih.delta.id}" name= "raikou_article" query= "select" raikou_article= "" update_time= "" where= "" > '${dataimporter.last_index_time}' > <field column= "id" name= "id" > <field column= "title" name= "title" > </field></field></entity></document></datasource></dataconfig> |
定义了数据导入、增量更新的查询语句。
web.xml 这段配置,可能有用
E:Mongodb-Redis-Nginxsolr-5.3.1serversolr-webappwebappWEB-INFweb.xml
1
2
3
4
5
6
7
8
9
|
<!-- People who want to hardcode their Solr Home directly into the WAR File can set the JNDI property here... --> <env-entry> <env-entry-name>solr/home</env-entry-name> <env-entry-value>J:SoftDataSolr</env-entry-value> <env-entry-type>java.lang.String</env-entry-type> </env-entry> |
Java程序访问
maven配置
1
2
3
4
5
|
<dependency> <groupid>org.apache.solr</groupid> solr-solrj</artifactid> <version> 5.3 . 1 </version> </dependency> |
包名:org.apache.solr.client.solrj
工具类
SolrHelper.java 查询(查询语句构造和执行查询,分页查询),更新,重建索引
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
|
import java.beans.PropertyDescriptor; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; import java.util.List; import org.apache.commons.lang3.StringUtils; import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.impl.HttpSolrClient; import org.apache.solr.client.solrj.response.QueryResponse; import org.apache.solr.common.SolrInputDocument; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.github.pagehelper.Page; /**查询(查询语句构造),更新,重建索引*/ public class SolrHelper<t> { protected final Logger logger = LoggerFactory.getLogger(SolrHelper. class ); private HttpSolrClient server; private StringBuffer queryString; public SolrHelper(String reqUrl) { server = new HttpSolrClient(reqUrl); queryString = new StringBuffer(); } public void andEquals(String fieldName, String val) { queryString.append( && ).append(fieldName).append(:).append(val); } public void orEquals(String fieldName, String val) { queryString.append( || ).append(fieldName).append(:).append(val); } public void andNotEquals(String fieldName, String val) { queryString.append( && ).append(-).append(fieldName).append(:) .append(val); } public void orNotEquals(String fieldName, String val) { queryString.append( || ).append(-).append(fieldName).append(:) .append(val); } public void andGreaterThan(String fieldName, String val) { queryString.append( && ).append(fieldName).append(:[).append(val) .append( TO ).append(*]); } public void orGreaterThan(String fieldName, String val) { queryString.append( || ).append(fieldName).append(:[).append(val) .append( TO ).append(*]); } public void andGreaterThanOrEqualTo(String fieldName, String val) { queryString.append( && ).append(fieldName).append(:[).append(val) .append( TO ).append(*]); } public void orGreaterThanOrEqualTo(String fieldName, String val) { queryString.append( || ).append(fieldName).append(:[).append(val) .append( TO ).append(*]); } public void andDateGreaterThan(String fieldName, Date val) { queryString.append( && ).append(fieldName).append(:[) .append(formatUTCString(val)).append( TO ).append(*]); } public void orDateGreaterThan(String fieldName, Date val) { queryString.append( || ).append(fieldName).append(:[) .append(formatUTCString(val)).append( TO ).append(*]); } public void andDateGreaterThanOrEqualTo(String fieldName, Date val) { queryString.append( && ).append(fieldName).append(:[) .append(formatUTCString(val)).append( TO ).append(*]); } public void orDateGreaterThanOrEqualTo(String fieldName, Date val) { queryString.append( || ).append(fieldName).append(:[) .append(formatUTCString(val)).append( TO ).append(*]); } public void andLessThan(String fieldName, String val) { queryString.append( && ).append(fieldName).append(:[).append(*) .append( TO ).append(val).append(]); } public void orLessThan(String fieldName, String val) { queryString.append( && ).append(fieldName).append(:[).append(*) .append( TO ).append(val).append(]); } public void andLessThanOrEqualTo(String fieldName, String val) { queryString.append( && ).append(fieldName).append(:[).append(*) .append( TO ).append(val).append(]); } public void orLessThanOrEqualTo(String fieldName, String val) { queryString.append( && ).append(fieldName).append(:[).append(*) .append( TO ).append(val).append(]); } public void andDateLessThan(String fieldName, Date val) { queryString.append( && ).append(fieldName).append(:[).append(*) .append( TO ).append(formatUTCString(val)).append(]); } public void orDateLessThan(String fieldName, Date val) { queryString.append( && ).append(fieldName).append(:[).append(*) .append( TO ).append(formatUTCString(val)).append(]); } public void andDateLessThanOrEqualTo(String fieldName, Date val) { queryString.append( && ).append(fieldName).append(:[).append(*) .append( TO ).append(formatUTCString(val)).append(]); } public void orDateLessThanOrEqualTo(String fieldName, Date val) { queryString.append( && ).append(fieldName).append(:[).append(*) .append( TO ).append(formatUTCString(val)).append(]); } public void andLike(String fieldName, String val) { queryString.append( && ).append(fieldName).append(:*).append(val) .append(*); } public void orLike(String fieldName, String val) { queryString.append( || ).append(fieldName).append(:*).append(val) .append(*); } public void andNotLike(String fieldName, String val) { queryString.append( && ).append(-).append(fieldName).append(:*) .append(val).append(*); } public void orNotLike(String fieldName, String val) { queryString.append( || ).append(-).append(fieldName).append(:*) .append(val).append(*); } public void andIn(String fieldName, String[] vals) { queryString.append( && ); in(fieldName, vals); } private void in(String fieldName, String[] vals) { List<string> list=Arrays.asList(vals); in(queryString,fieldName,list); } public void orIn(String fieldName, List<string> vals) { queryString.append( || ); in(queryString,fieldName,vals); } private static void in(StringBuffer queryString,String fieldName, List<string> vals) { queryString.append((); inStr(queryString, fieldName, vals); queryString.append()); } private static void inStr(StringBuffer queryString, String fieldName, List<string> vals) { int index = 0 ; for (String val : vals) { if ( 0 != index) { queryString.append( || ); } queryString.append(fieldName).append(:).append(val); index++; } } //instead of NOT [condition] use (*:* NOT [condition]) public void andNotIn(String fieldName, String[] vals) { List<string> list=Arrays.asList(vals); queryString.append(&&(); queryString.append(*:* NOT ); inStr(queryString, fieldName, list); queryString.append()); } public void andDateBetween(String fieldName, Date startDate, Date endDate) { queryString.append( && ).append(fieldName).append(:[) .append(formatUTCString(startDate)).append( TO ) .append(formatUTCString(endDate)).append(]); } public void orDateBetween(String fieldName, Date startDate, Date endDate) { queryString.append( || ).append(fieldName).append(:[) .append(formatUTCString(startDate)).append( TO ) .append(formatUTCString(endDate)).append(]); } public void andDateNotBetween(String fieldName, Date startDate, Date endDate) { queryString.append( && ).append(-).append(fieldName).append(:[) .append(formatUTCString(startDate)).append( TO ) .append(formatUTCString(endDate)).append(]); } public void orDateNotBetween(String fieldName, Date startDate, Date endDate) { queryString.append( && ).append(-).append(fieldName).append(:[) .append(formatUTCString(startDate)).append( TO ) .append(formatUTCString(endDate)).append(]); } public void andBetween(String fieldName, String start, String end) { queryString.append( && ).append(fieldName).append(:[).append(start) .append( TO ).append(end).append(]); } public void orBetween(String fieldName, String start, String end) { queryString.append( || ).append(fieldName).append(:[).append(start) .append( TO ).append(end).append(]); } public void andNotBetween(String fieldName, String start, String end) { queryString.append( && ).append(-).append(fieldName).append(:[) .append(start).append( TO ).append(end).append(]); } public void orNotBetween(String fieldName, String start, String end) { queryString.append( || ).append(-).append(fieldName).append(:[) .append(start).append( TO ).append(end).append(]); } public void andStartSub() { queryString.append( && (); } public void orStartSub() { queryString.append( || (); } public void endSub() { queryString.append()); } private String formatUTCString(Date d) { SimpleDateFormat sdf = new SimpleDateFormat(yyyy-MM-dd 'T' HH:mm:ss 'Z' ); String s = sdf.format(d); return s; } public int execQueryTotalCount() { SolrQuery params = handleQuery(); params.set(start, 0 ); params.set(rows, Integer.MAX_VALUE); QueryResponse response = null ; try { response = server.query(params); return response.getResults().size(); } catch (SolrServerException e) { logger.error(, e); } catch (IOException e) { logger.error(, e); } return 0 ; } public List<t> query(String sort, Class<t> beanClass) { SolrQuery params = handleQuery(); QueryResponse response = null ; List<t> list = null ; try { logger.info(SolyQuery: + params.toString()); response = server.query(params); list = (List<t>) response.getBeans(beanClass); } catch (SolrServerException e) { logger.error(SolrServerException, e); } catch (IOException e) { logger.error(IOException, e); } return list; } public Page<t> execQuery(Integer pageNo, Integer rows, String sort, Class<t> beanClass) { List<t> results = null ; Page<t> page = null ; SolrQuery params = handleQuery(); if (pageNo != null && rows != null && pageNo > 0 && rows > 0 ) { params.set(start, (pageNo - 1 ) * rows); params.set(rows, rows); } if ( null != sort && !.equals(sort)) { params.set(sort, sort); } QueryResponse response = null ; try { logger.info(SolyQuery WithPage: + params.toString()); response = server.query(params); results = (List<t>) response.getBeans(beanClass); page = new Page<t>(pageNo, rows, execQueryTotalCount()); page.addAll(results); } catch (SolrServerException e) { logger.error(SolrServerException, e); } catch (IOException e) { logger.error(IOException, e); } return page; } private SolrQuery handleQuery() { SolrQuery params = new SolrQuery(); String qryFinalStr = queryString.toString(); if (qryFinalStr.startsWith( && )) { qryFinalStr = qryFinalStr.replaceFirst( && , ); } else if (qryFinalStr.startsWith( || )) { qryFinalStr = qryFinalStr.replaceFirst( || , ); } // 子查询开头的关联符号 if (- 1 != qryFinalStr.indexOf(( && )) { qryFinalStr = qryFinalStr.replaceAll(\( \&\& , (); } if (- 1 != qryFinalStr.indexOf(( || )) { qryFinalStr = qryFinalStr.replaceAll(\( \|\| , (); } if (StringUtils.isBlank(qryFinalStr)) { qryFinalStr = *:*; } params.set(q, qryFinalStr); return params; } public void execDelete(String keyName, String keyVal) { try { server.deleteByQuery(keyName + : + keyVal); server.commit(); } catch (SolrServerException | IOException e) { logger.error(, e); } } public void execUpdate(T model) { Field[] fields = model.getClass().getDeclaredFields(); SolrInputDocument solrDoc = new SolrInputDocument(); try { for (Field f : fields) { PropertyDescriptor pd; pd = new PropertyDescriptor(f.getName(), model.getClass()); // 属性名 String fieldName = f.getName(); Method rM = pd.getReadMethod(); // 获得读方法 solrDoc.addField(fieldName, rM.invoke(model)); } server.add(solrDoc); server.commit(); } catch (Exception e) { logger.error(, e); } } public void execUpdate(SolrInputDocument solrDoc) { try { server.add(solrDoc); server.commit(); } catch (SolrServerException e) { logger.error(, e); } catch (IOException e) { logger.error(, e); } } /** * 重建索引和增量索引的接口 * * @param delta */ public void buildIndex( boolean delta) { SolrQuery query = new SolrQuery(); // 指定RequestHandler,默认使用/select query.setRequestHandler(/dataimport); String command = delta ? delta- import : full- import ; String clean = delta ? false : true ; String optimize = delta ? false : true ; query.setParam(command, command).setParam(clean, clean) .setParam(commit, true ).setParam(optimize, optimize); try { server.query(query); } catch (SolrServerException e) { logger.error(建立索引时遇到错误,delta: + delta, e); } catch (IOException e) { logger.error(建立索引时遇到错误,delta: + delta, e); } } }</t></t></t></t></t></t></t></t></t></t></string></string></string></string></string></t> |
代码使用示例:
1.常见的分页查询,更新单条数据
1
2
3
4
5
6
7
8
9
10
|
public static void main(String[] args) { SolrHelper<project> sh = new SolrHelper<project>( http: //host/solr/project); sh.andEquals(id, 32404 ); List<project> page = sh.execQuery( 1 , 10 , id desc, Project. class ); Project ps = page.get( 0 ); ps.setTotal( 3.1415 ); sh.execUpdate(ps); }</project></project></project> |
2.不修改,直接同步
1
2
3
4
5
6
|
public void synProject( long id) { ProjectSolrDto solrDto = projectMapper.selectSolrProjectSimple(id); SolrHelper<projectsolrdto> solrHelper = new SolrHelper<projectsolrdto>( solrProjectUrl); solrHelper.execUpdate(solrDto); }</projectsolrdto></projectsolrdto> |
3.同步某几个字段
1
2
3
4
5
6
7
8
9
10
11
|
public void synIntention(Long id) { Intention intention = intentionMapper.selectByPrimaryKey(id); SolrHelper<intention> solrHelper = new SolrHelper<intention>( solrIntentionUrl); SolrInputDocument solrDoc = new SolrInputDocument(); solrDoc.addField(id, intention.getId()); solrDoc.addField(intro, intention.getIntro()); solrDoc.addField(industry, intention.getIndustry()); solrHelper.execUpdate(solrDoc); } </intention></intention> |
4.删除
1
2
3
4
5
|
public void delFund(Long id) { SolrHelper<intention> solrHelper = new SolrHelper<intention>( solrFundUrl); solrHelper.execDelete(id, id.toString()); }</intention></intention> |
几点补充
1.需要有“定时器”,定时“全量更新”和“重建索引”,防止数据不一致,或者查询效率低。
2.SolrHelper中的代码,或者说Solr的相关代码,无非就是“增删改查CRUD”,比较特殊的
“重建索引”和为了执行查询,拼接查询条件的“And,Or”等工具方法。
3.分页有个实体类,用到了Github上的1个工具,个人觉得一般般,Page类的定义比较糟糕。
如有需要,自己引入,或者自行改造。
写在最后
IT互联网技术很多,更新很快,问题也很多,深入需要实践,深入需要时间。
技术方面的博学和专注,自己去平衡吧~
技术和技术之外的平衡,自己看着办哦~
Solr入门和实践以及我对Solr的8点理解的更多相关文章
- Solr入门之(4)配置文件solr.xml
<?xml version="1.0" encoding="UTF-8" ?> <!-- This is an example of a si ...
- 后端技术杂谈4:Elasticsearch与solr入门实践
阮一峰:全文搜索引擎 Elasticsearch 入门教程 作者:阮一峰 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://g ...
- Apache Solr入门教程(初学者之旅)
Apache Solr入门教程(初学者之旅) 写在前面:本文涉及solr入门的各方面,建议边思考边实践,相信能帮助你对solr有个清晰全面的了解并能简单实用. 在Apache Solr初学者教程的这个 ...
- Solr入门之SolrServer实例化方式
随着solr版本的不断升级, 差异越来越大, 从以前的 solr1.2 到现在的 solr4.3, 无论是类还是功能都有很大的变换, 为了能及时跟上新版本的步伐, 在此将新版本的使用做一个简单的入门说 ...
- Solr入门介绍
solr入门案例 solr是apache下的一个全文检索引擎系统. 我们需要在服务器上单独去部署solr, 通过它的客户端工具包solrJ, 就是一个 jar包, 集成到我们项目中来调用服务器中 ...
- Spring Data Solr入门
如何将Solr的应用集成到Spring中? SpringDataSolr就是为了方便Solr的开发所研制的一个框架,其底层是对SolrJ的封装. SpringDataSolr入门小Demo 首先目录结 ...
- solr入门
Solr采用Lucene搜索库为核心,提供全文索引和搜索开源企业平台,提供REST的HTTP/XML和JSON的API,如果你是Solr新手,那么就和我一起来入门吧!本教程以solr4.8作为测试环境 ...
- solr入门之搜索建议的几种实现方式和最终选取实现思路
上篇博客中我简单的讲了下solr自身的suggest模块来实现搜索建议.但是今天研究了下在solr自身的suggest中添加进去拼音来智能推荐时不时很方便.在次从网上搜集和整理思考了下该问题的解决. ...
- Solr学习笔记(5)—— Spring Data Solr入门
一.Spring Data Solr简介 前面已经介绍了通过solrJ来操作solr,那么我们如何将Solr的应用集成到Spring中?Spring Data Solr就是为了方便Solr的开发所研制 ...
随机推荐
- java中+=详解 a+=b和a=a+b的区别
short a=10; a+=4; System.out.println(a); 1.第一段代码的输出结果为14.执行流程是首先声明变量,判断赋给变量的初始值是否在short类型范围内,如果在则进行强 ...
- jfreechart在jsp中画图方式
这个问题一直困扰我好久,今天算是稍微找到一点解决思路了,在网上搜了好多列子,大部分的都是用servlet来实现画图,偶然找到一个列子用的是org.jfree.chart.servlet.Servlet ...
- [Shell]bash的良好编码实践
最好的bash脚本不仅可以工作,而且以易于理解和修改的方式编写.很多好的编码实践都是来自使用一致的变量名称和一致的编码风格.验证用户提供的参数是否正确,并检查命令是否能成功运行,以及长时间运行是否能保 ...
- Win10 64bit下安装GPU版Tensorflow+Keras
Tensorflow和Keras都是支持Python接口的,所以本文中说的都是搭建一个Python的深度学习环境. Keras是对Tensorflow或者Theano的再次封装,也就是以Tensorf ...
- RxJava 1.x 笔记:变换型操作符
在写这几篇 RxJava 笔记时,发现官方文档很久都没有更新啊. 一些前辈两年前写的学习笔记内容跟现在也基本一致,RxJava 2.x 的文档也基本没有,不知道是不是缺实习生. 本文内容为 RxJav ...
- kd树的原理
kd树就是一种对k维空间中的实例点进行存储以便对其进行快速检索的树形数据结构,可以运用在k近邻法中,实现快速k近邻搜索.构造kd树相当于不断地用垂直于坐标轴的超平面将k维空间切分. 假设数据 ...
- 【剑指offer】数组中的逆序对。C++实现
原创文章,转载请注明出处! 博客文章索引地址 博客文章中代码的github地址 # 题目 # 思路 基于归并排序的思想统计逆序对:先把数组分割成子数组,再子数组合并的过程中统计逆序对的数目.统计逆序对 ...
- git版本管理工具的使用
Git的一些资料 --关于git的介绍就此忽略了--- Git官网http://git-scm.com/ Visual Studio Tools for Git下载地址https://visualst ...
- BZOJ4976:宝石镶嵌(DP&思维)
Description 魔法师小Q拥有n个宝石,每个宝石的魔力依次为w_1,w_2,...,w_n.他想把这些宝石镶嵌到自己的法杖上,来提升 法杖的威力.不幸的是,小Q的法杖上宝石镶嵌栏太少了,他必须 ...
- Adobe Acrobat 9 Pro破解方法
首先安装Adobe Acrobat 9 Pro,默认安装在C盘. 如果你的系统盘是C盘,那么就删除:c:/Documents and Settings/All Users/Application Da ...