1.通过分词创建索引
a.根据存储数据对应的字段进行分词,得到分词库;Solr/Lucene采用的是一种反向索引,所谓反向索引:就是从关键字到文档的映射过程,保存这种映射这种信息的索引称为反向索引。
b.形成索引和分词库后,此时的索引就类似于我们使用的新华字典的比划偏旁,通过索引对应的文档编号,找到对应的文档。
这里使用的是IK分词器
安装和创建好solr对应的core之后我们进行简单的应用
注:此方法在SolrJUtil这个类下。
DEFAULT_URL="http://localhost:8080/solr/collection1";
public static HttpSolrServer getServer() {
synchronized (SolrJUtil.class) {
if (server == null) {
server = new HttpSolrServer(DEFAULT_URL);
server.setMaxRetries(1); // defaults to 0. > 1 not recommended.
server.setConnectionTimeout(5000); // 5 seconds to establish TCP
server.setSoTimeout(1000); // socket read timeout
server.setDefaultMaxConnectionsPerHost(100);
server.setMaxTotalConnections(100);
server.setFollowRedirects(false); // defaults to false
server.setAllowCompression(true);
}
}
return server;
}
2.获取数据,整理数据,对相应的字段进行分词,创建基本的分词库,将数据添加到solr document文档中
//部分伪代码片段
//步骤:
//1.获取solr core对应的连接
//2.删除集合中所有数据
//3.抓取和整理数据中获取的数据
//4.进行分词
//5.将分词构建成document存入solr中,将查询的其他数据构建成另外一个document存入solr中
//6.提交commit
public static boolean initDbIndex(Connection conn) {
ResultSet result = null;
HanyuPinyinOutputFormat spellFormat = new HanyuPinyinOutputFormat();
int i = 0;
try {
server.deleteByQuery("*:*");
Collection docs = new ArrayList();
List uniqueData = new ArrayList();
//此处从数据库获取你需要存储到搜索引擎里面的数据。
//result = 从数据库抓取的结果集
Map commentsCountMap = new HashMap();
while (result.next()) {
commentsCountMap.put(result.getLong("goodsId"), result.getInt("num"));
}
while (result.next()) {
Long goodsId = result.getLong("goodsId");
String goodsName = result.getString("goods_name");
String coverUrl = result.getString("cover_url");
String thumbUrl = result.getString("thumb_url");
String categoryId = result.getString("cat_id");
String categoryName = result.getString("cat_name");
//得到分词集合,存储到solr中之后,主要用来做提示和引导,例如用户在搜索框输入鞋,然后下面提示鞋子,篮球鞋等。
List suggestList = SolrJUtil.getFieldDefaultAnalysis("content",goodsName.toLowerCase());//手动分词
List goodsIds = new ArrayList();
for (String suggest : suggestList) {
SolrInputDocument doc = null;
if (!uniqueData.contains(suggest)) {// 不重复添加数据
String pinyin = PinyinHelper.toHanyuPinyinString(suggest,spellFormat, "");
doc = new SolrInputDocument();
doc.addField("id", UUIDGenerator.getUUID());
String trimSuggest = suggest.replaceAll(" ", "");//去除空格的中文索引
String pinyin_Text = pinyin.replaceAll(" ", "");//拼音
String firstSpellText = getFirstSpell(suggest);//拼音首字母
doc.addField("suggest", suggest);//中文建议
doc.addField("content", trimSuggest+" "+pinyin_Text+" "+ firstSpellText);//混合字段
uniqueData.add(suggest);
}
if(!goodsIds.contains(goodsId)){
String goodsName_py = PinyinHelper.toHanyuPinyinString(goodsName.replaceAll(" ", ""), spellFormat, "");
if(doc == null){
doc = new SolrInputDocument();
//doc.addField("id", UUIDGenerator.getUUID());
}
doc.setField("id", goodsId);
doc.addField("goodsId", goodsId);
doc.addField("goodsName", goodsName);
doc.addField("searchContent", goodsName.replaceAll(" ", "").toLowerCase()+goodsName_py);
if(prices.size()>0){
doc.addField("goodsPrice", prices.get(0));
}
if(minNums.size()>0){
doc.addField("minOrderNum", minNums.get(0));
}
doc.addField("coverUrl", Global.IMG_SERVER_URL+coverUrl);
doc.addField("thumbUrl", Global.IMG_SERVER_URL+thumbUrl);
doc.addField("categoryId", categoryId);
doc.addField("categoryName", categoryId+"_"+categoryName);
goodsIds.add(goodsId);
}
if(doc != null){
docs.add(doc);
}
}
}
try {
if(docs.size()>0){
UpdateResponse response = server.add(docs);
server.commit();
i = docs.size();
}
} catch (SolrServerException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
} catch (Exception e) {
LOG.error("initDbIndex errror:"+e.getMessage());
e.printStackTrace();
return false;
} finally {
try {
result.close();
conn.close(); // 4、关闭数据库
} catch (Exception e) {
LOG.error("initDbIndex errror:"+e.getMessage());
e.printStackTrace();
return false;
}
}
System.out.println("索引创建完毕,本次共更新" + i + "条数据!");
LOG.error("索引创建完毕,本次共更新" + i + "条数据!");
return true;
}
其他相关的工具类,主要用来进行分词.
获取指定字符串的分词,采用默认分词器
public static List getFieldDefaultAnalysis(String tokenField, String content) {
FieldAnalysisRequest request = new FieldAnalysisRequest("/analysis/field");
request.addFieldName(tokenField);// 字段名,随便指定一个支持中文分词的字段
request.setFieldValue("");// 字段值,可以为空字符串,但是需要显式指定此参数
request.setQuery(content);
FieldAnalysisResponse response = null;
try {
response = request.process(server);
} catch (Exception e) {
e.printStackTrace();
}
List results = new ArrayList();
Iterator it = response.getFieldNameAnalysis(tokenField).getQueryPhases().iterator();
while (it.hasNext()) {
AnalysisPhase pharse = (AnalysisPhase) it.next();
List list = pharse.getTokens();
for (TokenInfo info : list) {
results.add(info.getText());
}
}
return results;
}
获取汉语拼音首字母,英文字符不变
public static String getFirstSpell(String chinese) {
StringBuffer pybf = new StringBuffer();
char[] arr = chinese.toCharArray();
HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
for (int i = 0; i < arr.length; i++) {
if (arr[i] > 128) {
try {
String[] temp = PinyinHelper.toHanyuPinyinStringArray(
arr[i], defaultFormat);
if (temp != null) {
pybf.append(temp[0].charAt(0));
}
} catch (BadHanyuPinyinOutputFormatCombination e) {
e.printStackTrace();
}
} else {
pybf.append(arr[i]);
}
}
return pybf.toString().replaceAll("\\W", "").trim();
}
上述有些方法是不需要的,例如不需要使用拼音分词等。就不需最后一个。
完成上述之后,solr中的数据基本就初始化和准备完毕了,这个时候需要使用程序来进行查询了:
public String productList() {
SearchResult result = new SearchResult();
HttpSolrServer server = null;
server = SolrJUtil.getServer();
SolrQuery query = new SolrQuery();
keywords = keywords.trim();
query.set("q", "searchContent:*" + StringUtils.escapeAllSpecialChars(keywords) + "*");
query.set("spellcheck.q", StringUtils.escapeAllSpecialChars(keywords));
query.set("qt", "/spell");// 请求到spell
query.set("qf", "searchContent");// 查询字段
query.set("fl", "goodsId,goodsName,goodsPrice,minOrderNum,productUnit,coverUrl,isProvideSample,"
+ "transactions,countryCode,sourcePlace,productFeature,score,isEnquiry,isDiscount,fobMinPrice,fobMaxPrice,discount");// 返回字段
query.setStart((page - 1) * Global.PAGE_SIZE);//分页查询起始位置
query.setRows(Global.PAGE_SIZE);//分页大小
QueryResponse rp = server.query(query);
SolrDocumentList docList = rp.getResults();
result.setTotalRows(docList.getNumFound());
if (docList != null && docList.getNumFound() > 0) {
//获取文档中的数据,同时封装到javaBean中
String goodsName = (String) doc.getFieldValue("goodsName");
result.setProducts(products);
result.setSuccess(true);
} else {
SpellCheckResponse re = rp.getSpellCheckResponse();// 获取拼写检查的结果集
if (re != null) {
result.setSuccess(false);
result.setSuggestStr(re.getFirstSuggestion(keywords.replaceAll(" ", "")));
}
}
}
query.setHighlight(true);
query.addHighlightField("companyName");
query.setHighlightSimplePre("");
query.setHighlightSimplePost("");
Map>> highlightMap = queryResponse.getHighlighting();
List companyNameList = highlightMap.get(idStr).get("companyName");
if (CollectionUtils.isNotEmpty(companyNameList)) {
//使用这个结果替换掉document中的值
supplier.setCompanyName(companyNameList.get(0));
}
到此,基本上就已经介绍完了solr的配置,以及基本应用,可能讲述的有些凌乱。
注:上述代码都是伪代码,是提供一个步骤和思路。大家可以进行参考。
如果转载,请注明出处