Solr搜索引擎学习笔记之solrj应用实例

一.前期准备

solrj的作用是方便我们在Java服务端快捷调用solr API,对solr索引进行增删改查。

1.设置Field

编辑solr_home\solr_core\conf下的managed-schema文件

这些是原有的field,不用更改,其中"_text_"的text_general类型,在上一篇博客:Solr搜索引擎学习笔记之Solr服务器搭建 已设置了中文分词器smartcn







id

这些是新添加的field,可根据自己的实体类进行添加

	
	
	
	
	
	
	

这些是复制域,用于全文检索的字段

        
	
	
	
	

2.引入solrj包

	
	
	    org.apache.solr
	    solr-solrj
	    6.4.2 
	

二.solrj应用实例

1.创建SolrClient

  • 通过HttpSolrClient的构造方法创建SolrClient,这种方式官方从solr6.5开始已不推荐使用
    private HttpSolrClient solrClient=new HttpSolrClient("http://localhost:8080/solr/solr_core");

  • 使用HttpSolrClient内部类Builder构建SolrClient
    solrClient=new HttpSolrClient.Builder("http://localhost:8080/solr/solr_core").build();
    solrClient.setConnectionTimeout(500);
    solrClient.setSoTimeout(1000);
  • 通过Spring配置文件声明SolrClient
    
    
        
        
        
            
        
        
        
    

2.各类实现及jsp页面

  • java基础类:Book
get/set方法已省略
package com.lmz.entity;

import java.io.Serializable;
import java.sql.Timestamp;

import org.apache.solr.common.SolrInputDocument;

public class Book implements Serializable{
	/** serialVersionUID */
	private static final long serialVersionUID = 1L;
	
	/** id */
	private Long id;
	/** 书名 */
	private String bookName;
	/** 作者 */
	private Author author;
	/** 状态[0:下架;1:上架] */
	private Integer status;
	/** 内容 */
	private String content;
	/** 出版时间 */
	private Timestamp publishDate;

通过实体获取全文检索文档,实体属性对应上面配置field

	/**
	 * 获取solr全文检索对象
	 *
	 * @param book 
	 *           
	 * @return 全文检索对象
	 */
	public SolrInputDocument getSolrInputDocument(Book book) {
		SolrInputDocument document=new SolrInputDocument();
		document.addField("id", book.getId());
		document.addField("bookName", book.getBookName());
		document.addField("status", book.getStatus());
		document.addField("content", book.getContent());
		document.addField("publishDate", book.getPublishDate().getTime());
		if (book.getAuthor()!=null) {
			document.addField("author_id", book.getAuthor().getId());
			document.addField("author_name", book.getAuthor().getName());
			document.addField("author_nickname", book.getAuthor().getNickname());
		}
		return document;
	}

  • java基础类:Author
package com.lmz.entity;

import java.io.Serializable;

/**
 * 作者实体
 *
 */
public class Author implements Serializable{
	/** serialVersionUID */
	private static final long serialVersionUID = 1L;
	
	/** id */
	private Long id;
	/** 名字 */
	private String name;
	/** 昵称 */
	private String nickname;

  • solr工具类:SolrUtils

包括了索引的增删改,修改方法就是添加方法,id相同的数据会覆盖掉,查询方法过于复杂,不在此


package com.lmz.utils;

import java.io.IOException;
import java.util.Collection;
import java.util.List;

import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.response.UpdateResponse;
import org.apache.solr.common.SolrInputDocument;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.lmz.exception.SolrCheckException;

/**
 * solr工具类
 *
 */
@Component
public class SolrUtils {
	@Autowired
	private HttpSolrClient solrClient;
	
	public SolrUtils(){
		
	}

添加单个文档对象到检索库

	/**
	 * 添加对象到全文检索
	 * 
	 * @param document
	 * @throws IOException
	 * @throws SolrServerException
	 * @throws SolrCheckException
	 */
	public void add(SolrInputDocument document) throws SolrServerException, IOException, SolrCheckException {
		UpdateResponse response = solrClient.add(document);
		if (response.getStatus() == 0) {
			solrClient.commit();
		} else {
			throw new SolrCheckException("solr add error");
		}
	}

添加多个文档对象到检索库

	/**
	 * 添加对象到全文检索
	 * 
	 * @param document
	 * @throws IOException
	 * @throws SolrServerException
	 * @throws SolrCheckException
	 */
	public void add(Collection docs) throws IOException, SolrServerException, SolrCheckException {
		if (docs != null && docs.size() > 0) {
			UpdateResponse response = solrClient.add(docs);
			if (response.getStatus() == 0) {
				solrClient.commit();
			} else {
				throw new SolrCheckException("solr add error");
			}
		}
	}

上面是配置field的文档添加,若没有配置field,可在实体属性上使用@Field注解就行,也不必获取检索文档对象,便可直接添加

	/**
	 * 添加bean对象到全文检索
	 * @param object
	 * @throws IOException
	 * @throws SolrServerException
	 * @throws SolrCheckException
	 */
	public void addByBean(Object object) throws IOException, SolrServerException, SolrCheckException {
		UpdateResponse response=solrClient.addBean(object);
		if (response.getStatus() == 0) {
			solrClient.commit();
		} else {
			throw new SolrCheckException("solr add error");
		}
	}
	
	/**
	 * 添加bean对象到全文检索
	 * 
	 * @param document
	 * @throws IOException
	 * @throws SolrServerException
	 * @throws SolrCheckException
	 */
	public void addByBean(Collection objects) throws IOException, SolrServerException, SolrCheckException {
		if (objects != null && objects.size() > 0) {
			UpdateResponse response = solrClient.addBeans(objects);
			if (response.getStatus() == 0) {
				solrClient.commit();
			} else {
				throw new SolrCheckException("solr add error");
			}
		}
	} 
  

删除检索

	/**
	 * 在全文检索中移除对象
	 * 
	 * @param id
	 * @throws SolrServerException
	 * @throws IOException
	 * @throws SolrCheckException
	 */
	public void delete(String id) throws SolrServerException, IOException, SolrCheckException {
		UpdateResponse response=solrClient.deleteById(id);
		if (response.getStatus()==0) {
			solrClient.commit();
		} else {
			throw new SolrCheckException("solr delete error");
		}
	}
	
	/**
	 * 在全文检索中移除对象
	 * 
	 * @param id
	 * @throws SolrServerException
	 * @throws IOException
	 * @throws SolrCheckException
	 */
	public void delete(List ids) throws SolrServerException, IOException, SolrCheckException {
		UpdateResponse response=solrClient.deleteById(ids);
		if (response.getStatus()==0) {
			solrClient.commit();
		} else{
			throw new SolrCheckException("solr delete error");
		}
	}
	
	/**
	 * 删除全文检索的所有对象
	 * 
	 * @throws SolrServerException
	 * @throws IOException
	 * @throws SolrCheckException
	 */
	public void deleteAll() throws SolrServerException, IOException, SolrCheckException {
		UpdateResponse response=solrClient.deleteByQuery("*");
		if (response.getStatus()==0) {
			solrClient.commit();
		} else {
			throw new SolrCheckException("solr delete all error");
		}
	}

获取solr的server接口

	/**
	 * 获取solrClient
	 * @return
	 */
	public SolrClient getSolrClient() {
		return solrClient;
	}

  • 时间工具类:DateUtils
package com.lmz.utils;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 时间工具类
 *
 */
public class DateUtils {
	
	/**
	 * 根据当前时间获取id
	 * @return id
	 */
	public static Long getIDByDate() {
		SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMddmmss");
		String idStr=sdf.format(new Date());
		return new Long(idStr);
	}
}

  • solr检索实体类:SolrSearchBean
package com.lmz.bean;

import java.io.Serializable;
import java.util.List;

public class SolrSearchBean implements Serializable {
	/** SerialVersionUID */
	private static final long serialVersionUID = 1L;

	/** 关键字列表 */
	private List keywordList;

	/** 排序类型[0:倒序;1:正序] */
	private Integer orderType;

	/** 过滤条件:状态[0:下架;1:上架] */
	private Integer status;
	
	/** 是否高亮 */
	private Boolean ifHL;

	/** 当前页数 */
	private Integer pageNo;

	/** 页面大小 */
	private Integer pageSize;

  • 返回结果集:PageResult
package com.lmz.bean;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

/**
 * 分页结果类
 * @param 
 *
 */
public class PageResult implements Serializable{
	/** serialVersionUID */
	private static final long serialVersionUID = 1L;
	
	/** 当前页 */
	private Integer pageNo;
	/** 每页大小 */
	private Integer pageSize;
	/** 总数 */
	private Long count;
	/**总页数*/
	private Integer totalPage;
	/** list集合数据 */
	private List list;
	/** map集合数据 */
	private Map map;

  • 图书solr服务类:BookSolrService
package com.lmz.service;

import java.io.IOException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.lmz.bean.PageResult;
import com.lmz.bean.SolrSearchBean;
import com.lmz.entity.Author;
import com.lmz.entity.Book;
import com.lmz.exception.SolrCheckException;
import com.lmz.utils.SolrUtils;

/**
 * solr服务
 *
 */
@Service
public class BookSolrService {
	/** solr工具类 */
	@Autowired
	private SolrUtils solrUtils;

	/**
	 * 删除全部索引
	 * 
	 * @throws SolrServerException
	 * @throws IOException
	 * @throws SolrCheckException
	 */
	public void delAll() throws SolrServerException, IOException, SolrCheckException {
		solrUtils.deleteAll();
	}

	/**
	 * 添加索引
	 * 
	 * @param book
	 * @throws SolrCheckException
	 * @throws IOException
	 * @throws SolrServerException
	 */
	public void addSolrServer(Book book) throws SolrServerException, IOException, SolrCheckException {
		solrUtils.add(book.getSolrInputDocument(book));
	}

获取SolrQuery,设置检索条件

	/**
	 * 通过搜索实体获取SolrQuery
	 * 
	 * @param bean
	 *            搜索实体
	 * @return SolrQuery
	 */
	private SolrQuery getSolrQuery(SolrSearchBean bean) {
		SolrQuery query = new SolrQuery();

		StringBuffer sb_q = new StringBuffer();
		if (bean.getKeywordList() == null || bean.getKeywordList().size() == 0) {
			// 没有关键字则全查
			sb_q.append("*");
		} else {
			for (int i = 0; i < bean.getKeywordList().size(); i++) {
				if (i == 0) {
					sb_q.append(bean.getKeywordList().get(i));
				} else {
					sb_q.append(" AND ").append(bean.getKeywordList().get(i));
				}
			}
		}
		
		// 若是全查,取消高亮
		if ("*".equals(sb_q.toString())) {
			bean.setIfHL(false);
		}

		// 设置检索关键字,从"_text_"域中检索,也就是复制域中设置了该域的域
		query.set("q", "_text_:" + sb_q.toString());

		StringBuffer sb_fq = new StringBuffer();
		// 过滤状态
		if (bean.getStatus() != null && bean.getStatus() >= 0) {
			addStr(sb_fq);
			sb_fq.append("status:" + bean.getStatus());
		}

		// 设置过滤条件
		if (sb_fq.length() > 0) {
			query.set("fq", sb_fq.toString());
		}
		
		//指定查询输出结构格式
		query.set("wt", "json");

		// 设置分页
		// 开始页,solr第一页从0开始
		query.setStart(bean.getPageNo() - 1);
		// 每页大小
		query.setRows(bean.getPageSize());

		// 排序
		if (bean.getOrderType() != null && bean.getOrderType() >= 0) {
			if (bean.getOrderType() == 0) {
				query.addSort("publishDate", SolrQuery.ORDER.desc);
			} else {
				query.addSort("publishDate", SolrQuery.ORDER.asc);
			}
		}

		// 设置高亮
		if (bean.getIfHL()) {
			// 开启高亮
			query.setHighlight(true);
			// 添加高亮字段
			query.addHighlightField("bookName");
			query.addHighlightField("content");
			query.addHighlightField("author_name");
			query.addHighlightField("author_nickname");
			// 高亮的头部分
			query.setHighlightSimplePre("");
			// 高亮的尾部分
			query.setHighlightSimplePost("");
		}
		return query;
	}

搜索

	/**
	 * 搜索
	 * 
	 * @param bean
	 *            搜索实体
	 * @return 搜索结果集
	 * @throws SolrCheckException
	 */
	public PageResult search(SolrSearchBean bean) throws SolrCheckException {
		// 获取SolrQuery
		SolrQuery query = getSolrQuery(bean);
		// 搜索响应
		QueryResponse response = null;
		// 结果分页
		PageResult page = new PageResult();

		// 设置结果分页
		page.setPageNo(bean.getPageNo());
		page.setPageSize(bean.getPageSize());
		page.setCount(0L);
		page.setTotalPage(0);

		try {
			// 执行搜索
			response = solrUtils.getSolrClient().query(query);
			// 获取搜索结果文档
			SolrDocumentList documentList = response.getResults();
			// 获取所有高亮的字段
			Map>> highlightMap = response.getHighlighting();
			// 设置搜索总数
			page.setCount(documentList.getNumFound());
			// 设置总页数
			page.setTotalPage((int) (page.getCount() % page.getPageSize() == 0 ? page.getCount() / page.getPageSize()
					: page.getCount() / page.getPageSize() + 1));
			// 图书集合
			List books = new ArrayList();

			Book book = null;
			Author author = null;

			// 从结果文档中获取数据,并封装实体
			for (SolrDocument solrDocument : documentList) {
				book = new Book();
				book.setId(new Long(solrDocument.getFieldValue("id").toString()));
				book.setBookName(solrDocument.getFieldValue("bookName").toString());
				book.setContent(solrDocument.getFieldValue("content").toString());
				book.setStatus(new Integer(solrDocument.getFieldValue("status").toString()));
				book.setPublishDate(
						new Timestamp(Long.parseLong(solrDocument.getFieldValue("publishDate").toString())));
				author = new Author();
				author.setId(new Long(solrDocument.getFirstValue("author_id").toString()));
				author.setName(solrDocument.getFieldValue("author_name").toString());
				author.setNickname(solrDocument.getFirstValue("author_nickname").toString());

				// 获取并设置高亮字段
				if (bean.getIfHL()) {
					String id = solrDocument.getFieldValue("id").toString();
					
					/* 高亮集合里不是去不内容,仅仅只是含有高亮的部分,
					 * 如果字段数据比较大,那么搜索出来的数据就会截掉不属于高亮的部分,
					 * 因此这也是使用集合来封装数据的原因
					 */
					List bookNameList = highlightMap.get(id).get("bookName");
					List contentList = highlightMap.get(id).get("content");
					List authorNameList = highlightMap.get(id).get("author_name");
					List authorNicknameList = highlightMap.get(id).get("author_nickname");
					if (bookNameList != null && bookNameList.size() > 0) {
						book.setBookName(bookNameList.get(0));
					}
					if (contentList != null && contentList.size() > 0) {
						book.setContent(contentList.get(0));
					}
					if (authorNameList != null && authorNameList.size() > 0) {
						author.setName(authorNameList.get(0));
					}
					if (authorNicknameList != null && authorNicknameList.size() > 0) {
						author.setNickname(authorNicknameList.get(0));
					}
				}

				book.setAuthor(author);
				books.add(book);
			}

			page.setList(books);
		} catch (SolrServerException | IOException e) {
			throw new SolrCheckException("solr search error");
		}
		return page;
	}
	/**
	 * 在字符串末尾追加" and "
	 * 
	 * @param sb_fq
	 */
	private void addStr(StringBuffer sb_fq) {
		if (sb_fq.length() > 0) {
			sb_fq.append(" and ");
		}
	}

  • Controller:SolrTestController
package com.lmz.controller;

import java.io.IOException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import org.apache.commons.lang.StringUtils;
import org.apache.solr.client.solrj.SolrServerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.lmz.bean.PageResult;
import com.lmz.bean.SolrSearchBean;
import com.lmz.entity.Book;
import com.lmz.exception.SolrCheckException;
import com.lmz.service.BookSolrService;
import com.lmz.utils.DateUtils;

@Controller
public class SolrTestController {
	@Autowired
	private BookSolrService bookSolrService;
	
	/**
	 * 添加索引
	 * @param model
	 * @param book book对象,包含author对象
	 * @return
	 */
	@RequestMapping("/add")
	public String add(Model model,Book book) {
		String msg="添加成功";
		Long id=DateUtils.getIDByDate();
		book.setId(id);
		book.getAuthor().setId(id);
		book.setPublishDate(new Timestamp(new Date().getTime()));
		try {
			bookSolrService.addSolrServer(book);
		} catch (SolrServerException | IOException | SolrCheckException e) {
			msg="添加失败";
		}
		model.addAttribute("msg", msg);
		return "index";
	}
	
	/**
	 * 全文检索
	 * @param model
	 * @param bean solr搜索对象
	 * @return
	 */
	@RequestMapping("/search")
	public String search(Model model,SolrSearchBean bean) {
		//去除集合中空数据
		if (bean.getKeywordList()!=null) {
			for (int i = 0; i < bean.getKeywordList().size();) {
				if (StringUtils.isBlank(bean.getKeywordList().get(i))) {
					bean.getKeywordList().remove(i);
					if (i >= bean.getKeywordList().size()) {
						break;
					}
				} else {
					i++;
				}
			} 
		}
		//设置分页
		bean.setPageNo(1);
		bean.setPageSize(10);
		//分页结果
		PageResult page=null;
		//搜索
		try {
			page = bookSolrService.search(bean);
		} catch (SolrCheckException e) {
			//solr异常,组装空结果
			page=new PageResult();
			page.setCount(0l);
			page.setTotalPage(0);
			page.setPageNo(0);
			page.setPageSize(bean.getPageSize());
			page.setList(new ArrayList());
		}
		model.addAttribute("page", page);
		return "search";
	}

	/**
	 * 删除全部索引
	 * @return
	 */
	@RequestMapping("/del")
	@ResponseBody
	public String del() {
		try {
			bookSolrService.delAll();
		} catch (SolrServerException | IOException | SolrCheckException e) {
			return "删除失败";
		}
		return "删除成功";
	}
	
}

  • index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>




Insert title here




	添加索引
搜索
删除全部索引

${msg}


  • add.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>




Insert title here


	

  • search.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>




Insert title here



	
关键字
筛选条件
序号 id bookName status content publishDate author_id author_name author_nickname
${i.index} ${l.id} ${l.bookName} ${l.status} ${l.content} ${l.publishDate} ${l.author.id} ${l.author.name} ${l.author.nickname}
共${page.count}条记录 第${page.pageNo}页 共${page.totalPage}页


ok,整个实例已写完,下面来测试结果如何吧


三.测试

测试这里就进行添加和检索,删除因为就写了一个全删测试,就不进行了,修改的话就如同添加。

  • 添加索引

Solr搜索引擎学习笔记之solrj应用实例_第1张图片

点击添加后,到solr管理页面,查看是否添加成功

Solr搜索引擎学习笔记之solrj应用实例_第2张图片

这是检索全部数据,如果出现刚才新添加的数据就说明添加成功,如下:

Solr搜索引擎学习笔记之solrj应用实例_第3张图片

  • 全文检索

这是检索页面,如果没填关键字就会检索全部数据,现在就填写关键字:我的游戏,结果如下:

Solr搜索引擎学习笔记之solrj应用实例_第4张图片

ok,其它的搜索,就由你们完成了,现在整个实例就完成了......

你可能感兴趣的:(solr搜索引擎)