avatar

目录
solr使用说明

1.solr 的 使用说明

(1)solr core : solr 每个core 都是以 文档为单位,每个文档就是一条数据,每个文档上 有多个字段。 solr的查询结果就是一个个文档。

ugc_engine 为 ugc的文章 引擎 , 以文章作为文档,文章上 有多条属性

ugc_arr_engine  为 ugc的suggest 中的目的地引擎。 以目的地作为文档,每个目的地上带有多个属性。

2.solr 的配置

(1) schema.xml 中 配置的是 字段 和 字段类型

例子:

Code
1
2
3
4
5
6
7
8
9
10










说明:

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 en_id   主键:  高亮的时候,solr 会在对应的map中以 主键为key  存储数据

required="true" 必须有值,否则无法存入solr

stored="true" 是否存储,有些专门用来做搜索的不需要储存

indexed="true" 是否创建索引

type="text_bamboo" 字段的类型,一般可以使string boolean等类型,也可以是自定义,如text_bamboo ,自定义的中文分词器,在对应的 fieldType 中 查看具体的配置 。

复制字段 , contetn字段用来保存,search_content 用来分词 搜索

multiValued="true" 多值字段,一个字段可以是多值,设置后 为数组, 对该字段搜索,如果数组中有命中的数,即 该条 文章 被命中 ,如, destination[“北京”,“天津”]

动态字段,可以让solr接收未定义字段的数据

fieldType:定义字段类型

可以自家看下 tokenizer 和filter 去配置 字段类型,NGramFilterFactory可以用来分词, 做前缀匹配和中部匹配

字段类型说明

analyzer :index 表示 建索引的时候使用, query 标示 查询的时候使用, 实例测试 见 solr的 analyse 组件

通过tokenizer 去对数据做处理,然后filter 一层一层的去做处理

例子:这是一个前缀匹配的字段类型

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14


solr 自带的 分词类型
去除停词,暂时没使用
solr 提供的分词filter,可以用来做前缀匹配和 中部匹配, 会将 一个词 如 去哪儿网, 拆成 去 去哪 去哪儿 去哪儿网, 通过过min/maxGramSize 控制精度
最小值过滤,中文没用,




// 查询时 不进行前缀分词, 即 对查询不分词



效果截图

(2) solrConfig.xml 用来配置 solr的 整体配置,一般用不到, ugc的solr 是根据搜索组来的,中文分词等都是使用搜索的配置。

3.solr的 使用语法

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
在solr上 直接查询数据。 选择 solr core, query,添加参数,查询

参数说明:

q: 关键字查询, 如:en_id:3803042451 查询 en_id 字段()为xx的文章信息。

fq: 多条件查询,类似 where ,添加查询条件 如 q=search_des_path:北京 & fq= status:0 , 增加status:0的限制条件。同时满足的数据

sort:针对某字段排序,desc 降序,如 sort = property desc ,按照property 字段降序排列 。 (如 不加限制,默认按照查询相关度分数 降序排列)

start / rows : 从start条开始,展示rows行数据

fl: 字段过滤, 如果填写字段名,只显示该字段的数据,字段之间以 逗号分割, 如 en_id,id

facet:类似 sql的group ,分组,和分组下的结果

hl : 命中 高亮

facet: 统计,facet.field 设置字段名 如channel_id, 会在显示数据下facet_counts 里显示 ,符合当前查询条件的 该字段(channel_id)的每个数据对应的文章数量。

facet 只会统计 符合条件的文章数

在solrj 中使用

Code
1
2
sq.addFacetField(con.getFacetField());
sq.setFacet(true);

solr的facet 结果:

facet的结果处理:

Code
1
2
3
4
5
6
List counts= rs.getFacetField(con.getFacetField()).getValues();
Map map = new HashMap<>();
for(FacetField.Count c : counts){
map.put(c.getName() , c.getCount());
}
return map;

场景: 主要用在 ugc的 频道查询,出哪些频道

hl :高亮

场景: 搜索/suggest ,代码 :com.xxxx.xxxx.ugc.query.controller.SearchController

开启高亮:

Code
1
2
3
4
5
6
7
8
private void buildHighlightQuery(SolrQuery sq){
sq.setHighlight(true); // 开启高亮组件或用query.setParam("hl", "true");
sq.addHighlightField("search_title,search_content");// 高亮字段
sq.setHighlightSimplePre("");//高亮字段的模式
sq.setHighlightSimplePost("
");
sq.setHighlightFragsize(200);

使用时需要开启edismax

示例url:

Code
1
http://xxxxxxxxx/qsearch/ugc_engine/select?q=search_content%3A%E4%B8%8A%E6%B5%B7&fl=search_content&wt=json&indent=true&defType=edismax&stopwords=true&lowercaseOperators=true&hl=true&hl.fl=search_title%2Csearch_content&hl.simple.pre=%3Cem%3E&hl.simple.post=%3C%2Fem%3E&hl.requireFieldMatch=true

结果处理:

Code
1
2
3
4
Map> match = hl.get(articleMo.getDappId().getEid());// 获取高亮,即命中的文字
if(match != null){
if(match.get("search_title") != null){
articleMo.setTitle( getTitleByHl(match) );

solr 高亮结果示例:

(2)在Analysis 中 验证 具体的fieldType 的分词/查询效果

(3)上传数据,由数据抽取组提供,也可以手动传,json

a.直接操作,如删除某条数据,solr core的页面 Documents 中,添加置顶格式的内容

b.json文件,
Code
1
2
3
4
5
 post 方法,update/json?commit=true, 如 http://l-dapp2.m.vc.dev.cn0.xxx.com:9112/qsearch/ugc_engine/update/json?commit=true

在Hears中加,Content-type:json ,

在body中添加json文件(binary)

开始的时候使用mock的数据

(4)solr语句 示例。 如,ugc 业务中的 solr 搜索查询语句

Code
1
http://xxxxxxxxxxxxx/qsearch/ugc_engine/select?q=%E9%95%BF%E5%9F%8E&defType=edismax&qf=search_destination^1000+search_title^100+search_content^10&tie=1&sort=score+desc,quality+desc,audit_time+desc&hl=true&hl.fl=search_title,search_content&hl.simple.pre=%3Cfont+class%3D%22matched%22%3E&hl.simple.post=%3C/font%3E&hl.fragsize=200&start=0&rows=100&fl=score,en_id,id,title,imgs,audit_time,destination,departure,quality,user_id,user_en_id,user_info,channel_id,channel_en_id,content&fq=audit_time:+[+*+TO+NOW+]+AND+end_time:[+NOW+TO+*]&fq=status:0

3.ugc 中solr 引擎的使用。

(1)业务接口

Code
1
2
3
a.文章列表: ArticleController:list 方法,

b.搜索列表:SearchController :query 方法

(2)solr utils 使用(.SolrUtils)

Code
1
2
3
4
5
6
7
8
9
10
11
12
使用solr 工具类 SolrUtils, 使用solrj 连接基于zookeeper的solrClou/d,进行查询。

如: QueryResponse rs = SolrUtils.search(solrCollection,sq);

调用 public static QueryResponse search (String solrCollection , SolrQuery solrQuery )方法 ,

参数 solrCollection ,要查询的solr core的名字,solrQuery查询条件

其他方法说明:public static SolrDocumentList search , 返回结果是数据列表,不会有高亮和 分组等功能


该工具 会在com.xxxx.dapp.ugc.config.UGCSearchConfig 中, 在spring 启动的工程中 加载

(3)返回结果处理

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
(1)搜索-----高亮处理
ArticleMoService的buildHightlightContent方法,从reponse的hl中取出命中的数据,用来替换 solr的正常返回数据。

ugc:这块的逻辑是,命中的内容,获取命中词这句话,从这句话开始,返回给前台展示。

(2)正常处理

ArticleMo 方法 中进行对象转换

(3)频道 ----facet处理

SimpleChannelSearchService中的buildMappingByRs 方法

从返回的solr Response 中 根据facet的字段 即 频道 字段 获取facet的内容, 与数据库查出的频道 做过滤。如 List counts= rs.getFacetField(con.getFacetField()).getValues();

(4)ugc 业务中 solr 查询条件的构建:

Code
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
如 articleController ,  buildListSolrQurey方法

a.添加 过滤 查询 限制 ,出发地 departure 为中国,或者departure有 dep字段的 文章

sq.addFilterQuery("+(departure:"+ dep.trim() +" OR departure:中国)");

b.时间限制,solr中的时间默认是UTC时区,用 NOW 关键字 进行比较的时候,需要+8小时才是北京时间,如

sq.addFilterQuery("audit_time: [ * TO NOW+8HOUR ] AND end_time:[ NOW+8HOUR TO *]")


c.加权:用bq 参数 或qf 参数,区别:bq 在主查询基础上 增加权重, qf:将q中的参数在qf中指定的字段中 进行查询 并加上权重

如,文章列表的权重

bq:

sq.set("defType","edismax");
sq.add("bq","property:(1)^5000");//周边
sq.add("bq","property:(0)^1000");//中性
sq.add("bq","property:(2)^3");//游客

启用 edismax,增加bq参数,() 中的是字段对应的直^后为加的权重

qf:

sq.set("defType","edismax");
sq.set("qf","search_destination^1000 search_title^100 search_content^10");//权重,使有标签>无标签 =>标题正文都有>标题有>正文有
sq.set("tie","1");//tie 可以让三个字段命中的权重累加,如果没有tie 取权重最高的字段加权

qf 默认会在命中的三个字段中选择权重最高的 作为当前权重,可以通过设置tie :1 使得权重可以累加。


在solr query中 的fl 上加 score 字段,会显示该数据是多少评分, 在对应的solr query 后加 debug=true 参数,可以查看这次查询的评分构成
Code
1
2
3
4
5
6
7
bq参数示例:

http://xxxxxxxxxxxxx/qsearch/ugc_engine/select?q=*:*&fq=%2B(departure:%E5%8C%97%E4%BA%AC+OR+departure:%E4%B8%AD%E5%9B%BD)&fq=%2B(search_des_path:%E5%8C%97%E4%BA%AC)&fq=audit_time:+[+*+TO+NOW%2B8HOUR+]+AND+end_time:[+NOW%2B8HOUR+TO+*]&fq=status:0&defType=edismax&bq=property:(1)^5000&bq=property:(0)^1000&bq=property:(2)^3&bq=push_start_time:[*+TO+NOW%2B8HOUR+]+AND+push_end_time:[+NOW%2B8HOUR+TO+*]&sort=score+desc,push_start_time+desc,audit_time+desc,quality+desc&start=0&rows=100&fl=en_id,id,score,title,property

qf参数示例:

http://xxxxxxxxxxxxxxx/qsearch/ugc_engine/select?q=%E5%8C%97%E4%BA%AC&defType=edismax&qf=search_destination^1000+search_title^100+search_content^10&tie=1&sort=score+desc,quality+desc,audit_time+desc&hl=true&hl.fl=search_title,search_content&hl.simple.pre=%3Cfont+class%3D%22matched%22%3E&hl.simple.post=%3C/font%3E&hl.fragsize=200&start=0&rows=100&fl=score,en_id,id,title,destination,content&fq=audit_time:+[+*+TO+NOW+]+AND+end_time:[+NOW+TO+*]&fq=status:0

4.solr 引擎的 配置说明,dapp-ugc-search-

(1)调试说明

Code
1
2
3
4
5
a.   .dev 中配置要部署的server 名,  (可以ssh 通的)

b. 执行install脚本 ./install ,会把 当前工程 编译下,将配置 同步到远程 服务器上 重启solr引擎。

c. 调试使用,发布还是要走jenkins job, 流程比较规范

(2)新增core 说明 : 可以copy一个现成的core 然后修改schema,

Code
1
2
3
4
5
6
a.core下面的core.properties 中的 name: core的名称, dataDir 索引存放的位置

name=ugc_engine
dataDir=/home/q/qsearch-index/ugc_engine

b.schema.xml 中的引擎名称 修改,

5.solr 引擎的部署说明

6.solr的suggest 实现

ugc中的suggest 功能 是通过 select 实现的,使用单独的core ugc_arr_engine, 每一个doc就是一个目的地, 只进行前缀匹配 在字段类型上 使用EdgeNgram filter 来做前缀匹配

前缀匹配 字段类型:

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22





ignoreCase="true"
words="chinesestopword.txt"
enablePositionIncrements="true" />






ignoreCase="true"
words="chinesestopword.txt"
enablePositionIncrements="true" />





在 solr的Analyse 中进行分析, suggest的实现是 每次 select 去查询,而没有使用solr 本身呆的suggest的模块(因为用select 控制相对灵活,可以根据业务返回需要的字段,而suggest模块 就比较死板,所以采用select 模块 来实现suggest)

7.按照 指定 符号分词,

在des_path字段的格式 一般是 中国/北京/大连,想要将这句话 按照/ 为分隔符 分词,我们需要配置一下 fieldType 配置按照 分隔符分词

使用WordDelimiterFilterFactory filter 以关键字符为分隔符 进行分词

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19











ignoreCase="true"
words="stopwords.txt"
enablePositionIncrements="true"
/>




如图 所示,在WDF的filter 下 按照 / 分开了,

solr使用中遇到的一些问题

1.时间问题,

ugc中经常会用 当前时间做查询 ,如 文章是否有效(即 当前时间在 有效时间范围内),使用solr的 NOW 关键字,

solr的now 不是北京时间,使用的时候需要 加8HOUR 在进行比较

如:

Code
1
sq.addFilterQuery("audit_time: [ * TO NOW+8HOUR ] AND end_time:[ NOW+8HOUR TO *]");//文章是否可显示,必须当前时间在审核时间和下线时间之间

说明:

Code
1
* TO NOW+8HOUR 代表 所有 audit_time 字段 比 当前时间 小的 数据
Code
1
NOW+8HOUR TO *  代表 所有 end_time   字段 比 当前时间 大的 数据。

\2. solr 的 schema 字段 类型, 类型变更问题,如 Date类型

踩坑:solr的索引变换是一个缓慢的过程,之前尝试 将String 类型的字段改成date 类型的,但是 会造成 索引类型不匹配,最开始没什么问题,随时索引慢慢改变, 由于 不匹配导致 该字段的值 会变成 XXXXXXX origin value :xxx 的值,

如果想要改变 需要 刘能那边支持 帮忙刷数据,重新建立索引就可以了。

Code
1
 

3.solr 查询条件过多的问题

在同步平台数据的需求中, 需要传指定的1300多条数据, 使用qconfig+运营配置id的方式处理, 但是在拼接solr 查询条件的时候 会报错。

因为solr 只支持1024个查询项, 而 每一个id 都会被solr 拆分成一个查询项目,所以无法成功 , 这里修改了一下solr的配置文件

Code
1
4096

即 支持的最多查询项为4096个 。 注意这个选项 需要这个solr 下的所有core 都一样 才会生效。 即把剩余的core 都改成4096

4.solr 查询条件不支持

solr在查询中不支持 某些特殊字符, 如 [ ] ,比如 在一个查询中 departure : xxx [xxxx] solr 是会报错的。

解决方法:在list报错的接口 中添加一个用来过滤 特殊字符的方法,

Code
1
con.filterParam();

用来预处理特殊字符的问题。

5.solr的效率

solr 用作全文检索效率较高,但不适合一次返回很多条的数据的情况。在使用的过程中 尽可能少的 出现solr 返回大量的数据,之前测试 一次几百条,上千条 时间还好,但是不要 过多,也尽量避免 成百上千条的查询。

6.solr的相似度计算

solr 的默认相似度包含的 因素很多,比如词频等,导致 文档的score 不相等的 小数,影响后续的排序,如 首页的排序,是根据score 从高到低排,再根据push_weight 从高到低排序,这样就会导致 排序有问题。

在schema.xml中配置的similarity , 搜索team 写的, 只使用 权重,这样就可以 让评分 按照自己设定的权重 加分,从而使业务正确


附录:

solrUtils 工具类

Code
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

import com.google.common.base.Strings;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.response.UpdateResponse;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
* solr solrUtils
* Created by liuyudut.liu on 17-10-10.
* 该方法依赖于UGCSolrConfig 方法,在UGCSolrConfig 初始化前无法使用。
* 需要依赖 UGCSolrConfig 在spring 初始化的时候
* 通过该方法的updateSolrClient 为该方法初始化 并 为client赋值
*/

public class SolrUtils {
private final static Logger logger = LoggerFactory.getLogger(SolrUtils.class);

private static CloudSolrClient cloudSolrClient ;

private static String SOLR_MONITOR_KEY = "solr_search_ugc";

private static String SOLR_MONITOR_KEY_POST = "solr_search_ugc_post";

private static SolrClient getSolrClient() {
return cloudSolrClient;
}

private SolrUtils() {}

private static ThreadLocal threadLocal = new ThreadLocal() {
@Override
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
}
};

public static Date parse(String dateStr) throws ParseException {
return threadLocal.get().parse(dateStr);
}

public static String format(Date date) {
return threadLocal.get().format(date);
}

/**
* 更新CloudSolrClient变量
* @param zookhost
*/
public static void updateSolrClient(String zookhost){
if(Strings.isNullOrEmpty(zookhost)){
return;
}
CloudSolrClient temp = null;
try {
temp = new CloudSolrClient.Builder().withZkHost(zookhost).build();
}catch (Exception e){
throw new ValidationRuntimeException("solr zkHost 有误 连接失败",e);
}
if(temp != null){
synchronized (SolrUtils.class){
cloudSolrClient = temp;
}
}
}

/**
* 根据collection,Solrquery搜索数据
* @param solrCollection
* @return
*/

public static QueryResponse search (String solrCollection , SolrQuery solrQuery ){
if(solrQuery == null){
return null;
}
if(Strings.isNullOrEmpty( solrCollection ) ){
solrCollection = UGCSearchConfig.UGC_SEARCH_SOLR_COLLECTION_DEFAULT;
}
Timer.Context solrSearch = QCerberusHelper.buildReqTimer(SOLR_MONITOR_KEY, null,null).time();
SolrClient solrClient = getSolrClient();
logger.debug(" solrCollection : "+solrCollection +" solrQuery: "+solrQuery.toQueryString());
QueryResponse qr;
try {
qr = solrClient.query(solrCollection,solrQuery);
} catch (Exception e) {
logger.error(" solrCollection : "+solrCollection +" solrQuery: "+solrQuery.toQueryString() );
QCerberusHelper.buildThirdpartyReqExcetionCountMonitor(SOLR_MONITOR_KEY,e.getMessage());
throw new ValidationRuntimeException("solr 查询失败",e);
}finally {
QCerberusHelper.stop(solrSearch);
QCerberusHelper.count(SOLR_MONITOR_KEY);
}
return qr;
}

/**
* solr 查询 post 方法
* @param solrCollection
* @param solrQuery
* @return
*/
public static QueryResponse searchWithPost (String solrCollection , SolrQuery solrQuery ){
if(solrQuery == null){
return null;
}
if(Strings.isNullOrEmpty( solrCollection ) ){
solrCollection = UGCSearchConfig.UGC_SEARCH_SOLR_COLLECTION_DEFAULT;
}
Timer.Context solrSearchWithPost = QCerberusHelper.buildReqTimer(SOLR_MONITOR_KEY_POST, null,null).time();
SolrClient solrClient = getSolrClient();
logger.debug(" post query: solrCollection : "+solrCollection +" solrQuery: "+solrQuery.toQueryString());
QueryResponse qr;
try {
qr = solrClient.query(solrCollection,solrQuery, SolrRequest.METHOD.POST);
} catch (Exception e) {
throw new ValidationRuntimeException("solr 查询失败 post query: ",e);
}finally {
QCerberusHelper.stop(solrSearchWithPost);
}
return qr;
}


/**
* 根据collection,bMap,query搜索数据
* @param solrCollection
* @param query
* @param con
* @return
*/

public static SolrDocumentList search (String solrCollection , String query , SolrCommonCon con){
if(Strings.isNullOrEmpty(query)){
return null;
}
if(Strings.isNullOrEmpty( solrCollection ) ){
solrCollection = UGCSearchConfig.UGC_SEARCH_SOLR_COLLECTION_DEFAULT;
}
SolrClient solrClient = getSolrClient();
SolrQuery sq = new SolrQuery();
sq.setQuery(query);
if(con != null){
sq.set("indent", con.getIndent());
sq.set("wt", con.getWt());
sq.set("fl", con.getFl());
Integer row = con.getRow();
sq.setRows(row == null? 10 : row);
}
QueryResponse qr=null;
SolrDocumentList docs = null;
try {
qr=solrClient.query(solrCollection,sq);
docs = qr.getResults();
} catch (Exception e) {
throw new ValidationRuntimeException("solr 查询失败",e);
}
return docs;
}

/**
* 更新solr数据
* @param collection
* @param docs
* @return
*/
public static UpdateResponse updateSolrData(String collection , List docs) {
if(Strings.isNullOrEmpty(collection)){
throw new ValidationRuntimeException("solr 数据上传失败,collection 为空");
}
UpdateResponse ur = null;
try{
cloudSolrClient.deleteByQuery( collection,"*:*");
cloudSolrClient.add( collection , docs);
ur = cloudSolrClient.commit( collection ,false, false);
}catch (Exception e) {
throw new ValidationRuntimeException("solr 数据上传失败",e);
}
return ur;
}

public static void destory(){
try {
if(cloudSolrClient != null){
cloudSolrClient.close();
}
} catch (Exception e) {
throw new ValidationRuntimeException("solr 关闭连接失败",e);
}
}

/**
* @Description: 添加单个对象到索引
* @param object
* @throws IOException
* @throws SolrServerException
*/
public void addBean(String collection,Object object) {
try {
cloudSolrClient.addBean(collection, object);
cloudSolrClient.commit(false, false);
}catch(Exception e){
throw new QRuntimeException("solr 数据添加失败",e);
}
}
/**
* @Description: 添加集合到索引
* @param lists
* @throws IOException
* @throws SolrServerException
*/
public void addBeans(String collection ,List lists)
{
try {
cloudSolrClient.addBeans(collection,lists);
cloudSolrClient.commit(false, false);
}catch(Exception e){
throw new QRuntimeException("solr 数据添加失败",e);
}
}
/**
* @Description: 根据id删除记录
* @param idName,id
* @throws IOException
* @throws SolrServerException
*/
public void deleteById(String collection, String idName, Object id) {
try {
cloudSolrClient.deleteByQuery(collection,idName + ":" + id.toString());
cloudSolrClient.commit(false, false);
} catch (Exception e) {
throw new QRuntimeException("solr 数据删除失败",e);
}
}
/**
* @Description: 添加单个对象到索引
* @throws IOException
* @throws SolrServerException
*/
public void deleteAll(String collection) {
try {
cloudSolrClient.deleteByQuery(collection,"*:*");
cloudSolrClient.commit(false, false);
} catch (Exception e) {
throw new QRuntimeException("solr 数据删除失败",e);
}
}

/**
* @Description: 特殊符号过滤

*/
public static String filterCharacter(String query) {
if(Strings.isNullOrEmpty( query ) ){
return null;
}
if(query.contains("[") || query.contains("]")){
query = query.replace("[","");
return query.replace("]","");
}
return null;
}

}
文章作者: 美式不加糖
文章链接: http://yoursite.com/2020/02/04/solr%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 湖畔小屋
打赏
  • 微信
    微信
  • 支付寶
    支付寶