welcome to xlongwei.com

欢迎大家一起学习、交流、分享


QQ:9167702333 邮箱:admin@xlongwei.com

solr索引和搜索实例


分类 Java   关键字 分享   标签 java   web   发布 hongwei  1429581386351
注意 转载须保留原文链接,译文链接,作者译者等信息。  
solr.war发布介绍了solr服务器的配置和部署,这里再介绍一下创建索引和执行搜索的代码实例,通常会用到两个功能:
  • suggest,搜索词提示,例如:输入“专”,可以自动提示“专家”
  • search,执行搜索

solr提供注解功能简化了lucene的创建索引过程,@Field注解索引文档字段,hilights是高亮置换字段
public class SolrSearch implements Serializable {
private @Field Long id;
private @Field Long articleId;
private @Field Long categoryId;
private @Field Long authorId;
private @Field String categoryName;
private @Field String authorName;
private @Field String authorNamePinyin;
private @Field String authorNamePinyinHeader;
private @Field String title;
private @Field String body;
private @Field String tags;

private List<String> hilights;

文章搜索服务
public interface SearchService {
/** 创建索引 */
Result<Boolean> createIndex();
/** 更新文档 */
Result<Boolean> updateIndex(Long id);
/**
* @param field *, title, body, categoryId:90 tags
* @param key *, 专家, -1
*/
Result<String> search(String field, String key, Pager pager);
/**
* @param field *, ttle, authorName, body ...
* @param key 专家, 专, zj, zhuanjia
*/
Result<SolrSuggest> suggest(String field, String key);
}
以下代码仅供参考(search方法其他封装的复杂了,应该参考solr的query语法:*:*等方式,field+key反而不如query灵活,能够支持复杂条件搜索)
@Service("searchService")
public class SearchServiceImpl implements SearchService, DisposableBean {
@Autowired ArticleService articleService;
@Autowired UserService userService;
@Autowired TongjiService tongjiService;

public Result<Boolean> createIndex() {
List<?> beans = getSolrBeans();
if(beans!=null && beans.size()>0) {
SolrServer server = getSolrServer();
try {
server.deleteByQuery("*:*");
server.addBeans(beans);
server.optimize();
server.commit();
return Result.newSuccess(true);
} catch (Exception e) {
return Result.newException(e);
}
}
return Result.newFailure(-1, "");
}

public Result<Boolean> updateIndex(Long id) {
Object bean = getSorlBean(id);
if(bean!=null) {
SolrServer server = getSolrServer();
try {
server.addBean(bean);
server.commit();
return Result.newSuccess(true);
}catch (Exception e) {
return Result.newException(e);
}
}
return Result.newFailure(-1, "not found bean with id="+id);
}

public Result<String> search(String field, String key, Pager pager) {
if (StringUtils.trimToNull(field)==null) field = "*";
if (StringUtils.trimToNull(key)==null) key = "*";

boolean checkAutoComplete = !"*".equals(key) && !"-1".equals(key);
doGetPager(field, key, pager);

//如果有key和value,并且捜不到结果,则搜索自动提示的第一个
if(checkAutoComplete && pager.getTotalRows() == 0 && pager.getCurrentPage() == 1) {
SolrSuggest searchSuggest = suggest(field, key).getObject();
String[] suggestions = searchSuggest.getSuggestions();
if(suggestions != null && suggestions.length > 0) {
doGetPager(field, StringUtils.join(suggestions, " OR "), pager);
}
}

return Result.newSuccess(checkAutoComplete ? key : "");
}

public Result<SolrSuggest> suggest(String field, String key) {
SolrSuggest searchSuggest = new SolrSuggest();
searchSuggest.setQuery(key);
if (StringUtils.trimToNull(key) != null) {
SolrServer server = getSolrServer();
SolrQuery query = new SolrQuery();
//field可以携带条件如categoryId:90 tags,setQuery之后恢复准确field
int space = field.lastIndexOf(' ');
field = space>-1 ? field.substring(space+1) : field;
query.setQuery(space>-1 ? field.substring(0, space) : "*:*");
query.setFacet(true);
if(StringUtils.trimToNull(field) == null) field = "*";
boolean bAll = "*".equals(field);
boolean bPinYin = StringUtils.isAsciiPrintable(key);
if(bAll) {
query.addFacetField("title");
query.addFacetField("authorName","categoryName","body","tags");
if(bPinYin) {
query.addFacetField("authorNamePinyin");
query.addFacetField("authorNamePinyinHeader");
}
}else {
query.addFacetField(field);
}
query.setFacetPrefix(key);
query.setFacetMinCount(1);
int suggestNumber = NumberUtil.parseInt(GlobalConfig.getProperty("solr.suggest.number"), 5);
query.setFacetLimit(suggestNumber + 1);
searchSuggest.setNumber(suggestNumber);
try {
QueryResponse rsp = server.query(query);

if(bAll) {
getFacetField("title", key, searchSuggest, rsp);
getFacetField("authorName", key, searchSuggest, rsp);
getFacetField("categoryName", key, searchSuggest, rsp);
getFacetField("body", key, searchSuggest, rsp);
getFacetField("tags", key, searchSuggest, rsp);
}else {
getFacetField(field, key, searchSuggest, rsp);
}

if(bAll && bPinYin && (searchSuggest.isFull() == false)) {
getPinYin(rsp, key, searchSuggest);
}
} catch (SolrServerException e) {
e.printStackTrace();
}
}
return Result.newSuccess(searchSuggest);
}

private void doGetPager(String field, String key, Pager pager) {
SolrServer server = getSolrServer();
SolrQuery query = new SolrQuery();
boolean hilighted = !"*".equals(key), bAll = "*".equals(field);
if(bAll) {
query.setQuery("title:"+key+" authorName:"+key+" categoryName:"+key+" body:"+key+" tags:"+key);
}else if("-1".equals(key)) {
query.setQuery(field);
}else {
query.setQuery(field+":"+key);

//field可以携带条件如categoryId:90 tags,setQuery之后恢复准确field
int space = field.lastIndexOf(' ');
field = space>-1 ? field.substring(space+1) : field;
}
query.setStart(pager.getStartRow());
query.setRows(pager.getPageSize());
//返回部分字段
query.setFields("articleId", "categoryId", "categoryName", "authorId", "authorName", "title", "body", "tags");

//高亮显示
if(hilighted) {
if(bAll) {
query.addHighlightField("title");
query.addHighlightField("authorName");
query.addHighlightField("body");
}else {
query.addHighlightField(field);
}
query.setHighlight(true); // 开启高亮组件
query.setHighlightSimplePre("<font color='red'>");//标记,高亮关键字前缀
query.setHighlightSimplePost("</font>");//后缀
query.setHighlightFragsize(150);// 分片默认100
}

QueryResponse rsp;
try {
rsp = server.query(query);
if(pager.notInitialized()) {
long numFound = rsp.getResults().getNumFound();
pager.init((int)numFound);
}
List<SolrSearch> list = rsp.getBeans(SolrSearch.class);
if(hilighted) {
Map<String, Map<String, List<String>>> highlighting = rsp.getHighlighting();
for(SolrSearch article : list) {
Map<String, List<String>> map = highlighting.get(String.valueOf(article.getId()));
if(map != null) {
String[] bookSearchHilights = new String[5];
if(bAll) {
List<String> hilights = map.get("title");
if(hilights != null && hilights.size() > 0) {
bookSearchHilights[0] = hilights.get(0);
}
hilights = map.get("authorName");
if(hilights != null && hilights.size() > 0) {
bookSearchHilights[1] = hilights.get(0);
}
hilights = map.get("categoryName");
if(hilights != null && hilights.size() > 0) {
bookSearchHilights[2] = hilights.get(0);
}
hilights = map.get("body");
if(hilights != null && hilights.size() > 0) {
bookSearchHilights[3] = hilights.get(0);
}
}else if(!"-1".equals(key)){
List<String> hilights = map.get(field);
if(hilights != null && hilights.size() > 0) {
bookSearchHilights[4] = hilights.get(0);
}
}
article.setHilights(Arrays.asList(bookSearchHilights));
}
}
}
pager.setElements(list);
} catch (SolrServerException e) {
e.printStackTrace();
}
}

private void getFacetField(String field, String key, SolrSuggest searchSuggest, QueryResponse rsp) {
FacetField facetField = rsp.getFacetField(field);
List<Count> countList = facetField != null ? facetField.getValues() : null;
if(countList != null && countList.size() > 0) {
for (int i = 0; i < countList.size(); i++) {
Count count = countList.get(i);
if(searchSuggest.isFull()) break;
String suggestion = StringUtils.trim(count.getName());
if(!key.equals(suggestion) && !searchSuggest.contains(suggestion)) searchSuggest.addSugguest(suggestion, (int)count.getCount());
}
}
}

private void getPinYin(QueryResponse queryResponse, String key, SolrSuggest searchSuggest){
List<Count> pinyincountList = queryResponse.getFacetField("authorNamePinyin").getValues();
List<Count> pinyincountList2 = queryResponse.getFacetField("authorNamePinyinHeader").getValues();
if((pinyincountList == null || pinyincountList.size() == 0) && (pinyincountList2 == null || pinyincountList2.size() == 0)) return;

SolrServer server = getSolrServer();
SolrQuery query = new SolrQuery();
StringBuilder q = new StringBuilder();
List<Long> counts = new ArrayList<Long>();
if(pinyincountList != null && pinyincountList.size() > 0) {
for(Count count : pinyincountList) {
q.append("authorNamePinyin:"+count.getName()+" ");
counts.add(count.getCount());
}
}
if(pinyincountList2 != null && pinyincountList2.size() > 0) {
for(Count count : pinyincountList2) {
q.append("authorNamePinyinHeader:"+count.getName()+" ");
counts.add(count.getCount());
}
}
query.setQuery(q.toString());
query.setStart(0);
query.setRows(5);
try {
QueryResponse rsp = server.query(query);
List<SolrSearch> searchList = rsp.getBeans(SolrSearch.class);

if (searchList!=null && searchList.size() > 0){
for (int i = 0 ;i<searchList.size();i++ ){
if(searchSuggest.isFull()) break;
String suggestion = StringUtils.trim(searchList.get(i).getAuthorName());
if(!key.equals(suggestion) && !searchSuggest.contains(suggestion)) searchSuggest.addSugguest(suggestion, counts.get(i).intValue());
}
}

} catch (SolrServerException e) {
e.printStackTrace();
}
}

private String getSolrService() {
return GlobalConfig.getProperty("solr.service");
}

@SuppressWarnings("rawtypes")
private List<?> getSolrBeans() {
SqlBuilder sqlBuilder = new SqlBuilder();
sqlBuilder.select("count(a.id)");
sqlBuilder.from("article a left join category c on a.category_id=c.id left join user u on a.author_id=u.id left join user_profile p on u.id=p.id");
sqlBuilder.eq("a.publish", "1");
sqlBuilder.eq("a.deleted", "0");

Result<Integer> count = tongjiService.count(sqlBuilder);
if(!count.hasObject()) return null;

Pager pager = new Pager();
pager.setPageSize(20);
pager.init(count.getObject());

List<SolrSearch> solrSearchList = new ArrayList<>(pager.getTotalRows());
sqlBuilder.select("a.id aid,a.article_id,c.id cid,c.name,u.id uid,p.real_name,a.title,a.tags,a.body");
sqlBuilder.limit(PagerUtil.limit(pager));
Result<List> list = tongjiService.list(sqlBuilder);
while(list.hasObject() && list.getObject().size()>0) {
for(Object obj : list.getObject()) {
Object[] arr = (Object[])obj;
int idx = 0;
SolrSearch solrSearch = new SolrSearch();
solrSearch.setId(NumberUtil.parseLong(ObjectUtils.toString(arr[idx++]), null));
solrSearch.setArticleId(NumberUtil.parseLong(ObjectUtils.toString(arr[idx++]), null));
solrSearch.setCategoryId(NumberUtil.parseLong(ObjectUtils.toString(arr[idx++]), null));
solrSearch.setCategoryName(ObjectUtils.toString(arr[idx++]));
solrSearch.setAuthorId(NumberUtil.parseLong(ObjectUtils.toString(arr[idx++]), null));
solrSearch.setAuthorName(ObjectUtils.toString(arr[idx++]));
solrSearch.setTitle(ObjectUtils.toString(arr[idx++]));
solrSearch.setTags(ObjectUtils.toString(arr[idx++]));
solrSearch.setBody(ObjectUtils.toString(arr[idx++]));

String realName = solrSearch.getAuthorName();
if(StringUtils.isNotBlank(realName)) {
String pinyinHeader = PinyinUtil.getPinyinHeader(realName);
String pinyin = PinyinUtil.getPinyin(realName);
solrSearch.setAuthorNamePinyin(pinyin);
solrSearch.setAuthorNamePinyinHeader(pinyinHeader);
}

solrSearchList.add(solrSearch);
}

int currentPage = pager.getCurrentPage();
if(currentPage>=pager.getTotalPages()) break;
pager.page(pager.getCurrentPage()+1);
if(currentPage>=pager.getCurrentPage()) break;

sqlBuilder.limit(PagerUtil.limit(pager));
list = tongjiService.list(sqlBuilder);
}

return solrSearchList;
}

private Object getSorlBean(Long id) {
Result<Article> retrieveArticle = articleService.retrieve(id);
if(retrieveArticle.hasObject()) {
Article article = retrieveArticle.getObject();

SolrSearch solrSearch = new SolrSearch();
solrSearch.setId(article.getId());
solrSearch.setArticleId(article.getArticleId());
solrSearch.setAuthorId(article.getAuthorId());
solrSearch.setCategoryId(article.getCategoryId());
solrSearch.setTitle(article.getTitle());
solrSearch.setBody(article.getBody());
solrSearch.setTags(article.getTags());

Result<UserProfile> userProfileResult = userService.getUserProfile(article.getAuthorId());
if(userProfileResult.hasObject()) {
UserProfile userProfile = userProfileResult.getObject();
String realName = userProfile.getRealName();
solrSearch.setAuthorName(realName);
if(StringUtils.isNotBlank(realName)) {
String pinyinHeader = PinyinUtil.getPinyinHeader(realName);
String pinyin = PinyinUtil.getPinyin(realName);
solrSearch.setAuthorNamePinyin(pinyin);
solrSearch.setAuthorNamePinyinHeader(pinyinHeader);
}
}
return solrSearch;
}
return null;
}

public void destroy() throws Exception {
if(server!=null) server.shutdown();
}

private HttpSolrServer server = null;
private SolrServer getSolrServer() {
if(server==null) {//共用server,或者用完后shutdown()
server = new HttpSolrServer(getSolrService());
server.setSoTimeout(10000);
server.setConnectionTimeout(3000);
server.setDefaultMaxConnectionsPerHost(100);
server.setMaxTotalConnections(100);
server.setFollowRedirects(false);
server.setAllowCompression(true);
}
return server;
}
}