1.solr 的 使用说明
(1)solr core : solr 每个core 都是以 文档为单位,每个文档就是一条数据,每个文档上 有多个字段。 solr的查询结果就是一个个文档。
ugc_engine 为 ugc的文章 引擎 , 以文章作为文档,文章上 有多条属性
ugc_arr_engine 为 ugc的suggest 中的目的地引擎。 以目的地作为文档,每个目的地上带有多个属性。
2.solr 的配置
(1) schema.xml 中 配置的是 字段 和 字段类型
例子:
说明:
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 一层一层的去做处理
例子:这是一个前缀匹配的字段类型
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的 使用语法
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 中使用
1 2
| sq.addFacetField(con.getFacetField()); sq.setFacet(true);
|
solr的facet 结果:
![]()
facet的结果处理:
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
开启高亮:
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:
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
|
结果处理:
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文件,
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 搜索查询语句
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)业务接口
1 2 3
| a.文章列表: ArticleController:list 方法,
b.搜索列表:SearchController :query 方法
|
(2)solr utils 使用(.SolrUtils)
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)返回结果处理
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 查询条件的构建:
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 参数,可以查看这次查询的评分构成
|
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)调试说明
1 2 3 4 5
| a. .dev 中配置要部署的server 名, (可以ssh 通的)
b. 执行install脚本 ./install ,会把 当前工程 编译下,将配置 同步到远程 服务器上 重启solr引擎。
c. 调试使用,发布还是要走jenkins job, 流程比较规范
|
(2)新增core 说明 : 可以copy一个现成的core 然后修改schema,
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 来做前缀匹配
前缀匹配 字段类型:
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 以关键字符为分隔符 进行分词
如
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 在进行比较
如:
1
| sq.addFilterQuery("audit_time: [ * TO NOW+8HOUR ] AND end_time:[ NOW+8HOUR TO *]");//文章是否可显示,必须当前时间在审核时间和下线时间之间
|
说明:
1
| * TO NOW+8HOUR 代表 所有 audit_time 字段 比 当前时间 小的 数据
|
1
| NOW+8HOUR TO * 代表 所有 end_time 字段 比 当前时间 大的 数据。
|
\2. solr 的 schema 字段 类型, 类型变更问题,如 Date类型
踩坑:solr的索引变换是一个缓慢的过程,之前尝试 将String 类型的字段改成date 类型的,但是 会造成 索引类型不匹配,最开始没什么问题,随时索引慢慢改变, 由于 不匹配导致 该字段的值 会变成 XXXXXXX origin value :xxx 的值,
如果想要改变 需要 刘能那边支持 帮忙刷数据,重新建立索引就可以了。
3.solr 查询条件过多的问题
在同步平台数据的需求中, 需要传指定的1300多条数据, 使用qconfig+运营配置id的方式处理, 但是在拼接solr 查询条件的时候 会报错。
因为solr 只支持1024个查询项, 而 每一个id 都会被solr 拆分成一个查询项目,所以无法成功 , 这里修改了一下solr的配置文件
即 支持的最多查询项为4096个 。 注意这个选项 需要这个solr 下的所有core 都一样 才会生效。 即把剩余的core 都改成4096
4.solr 查询条件不支持
solr在查询中不支持 某些特殊字符, 如 [ ] ,比如 在一个查询中 departure : xxx [xxxx] solr 是会报错的。
解决方法:在list报错的接口 中添加一个用来过滤 特殊字符的方法,
用来预处理特殊字符的问题。
5.solr的效率
solr 用作全文检索效率较高,但不适合一次返回很多条的数据的情况。在使用的过程中 尽可能少的 出现solr 返回大量的数据,之前测试 一次几百条,上千条 时间还好,但是不要 过多,也尽量避免 成百上千条的查询。
6.solr的相似度计算
solr 的默认相似度包含的 因素很多,比如词频等,导致 文档的score 不相等的 小数,影响后续的排序,如 首页的排序,是根据score 从高到低排,再根据push_weight 从高到低排序,这样就会导致 排序有问题。
在schema.xml中配置的similarity , 搜索team 写的, 只使用 权重,这样就可以 让评分 按照自己设定的权重 加分,从而使业务正确
附录:
solrUtils 工具类
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; }
}
|