@Component
public class SolrUtil {
@Autowired
private TbItemMapper tbItemMapper;
@Autowired
private SolrTemplate solrTemplate;
public void importItemData() {
TbItemExample example = new TbItemExample();
Criteria criteria = example.createCriteria();
criteria.andStatusEqualTo("1");
List<TbItem> itemList = tbItemMapper.selectByExample(example);
for (TbItem item : itemList) {
//spec在搜索中是动态域,在实体类中建立一个属性map,并且要加上@Dynamic和@Field("item_spec_*")注解
//JSON.parseArray 是针对[]开头的字符串转换成集合 ,JSON.parseObject是针对{}开头的字符串转换成集合
//
Map map = JSON.parseObject(item.getSpec(), Map.class);
item.setMapSpec(map);
}
solrTemplate.saveBeans(itemList);
solrTemplate.commit();
}
public static void main(String[] args) {
//@component (把普通pojo实例化到spring容器中,相当于配置文件中的<bean id="" class=""/>)
//原生读取xml文件的方式,第一个classpath如果不加*则只能读取当前工程下的配置文件,第二个*是通配符表示以applicationContext开头的xml都要去读
//然而当前需要读取不仅是当前工程的xml还要读取Dao的xml,且其下配置文件是applicationContext-service.xml
ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:spring/applicationContext*.xml");
//spring读取bean创建一个队象,默认是以当前类第一个字母小写来创建队象
SolrUtil solrUtil = (SolrUtil) context.getBean("solrUtil");
solrUtil.importItemData();
}
}
关键字高亮查询
@Service(timeout=5000)
public class ItemSearchServiceImpl implements ItemSearchService {
@Autowired
private SolrTemplate solrTemplate;
/**
* item_keyword是solr的一个复制域,其值包括item_title,item_category,item_seller,item_brand
* 所以搜索匹配实体用item_keyword比较全面
*/
@Override
public Map search(Map searchMap) {
Map map = new HashMap();
/*Query query = new SimpleQuery("*:*");
Criteria criteria = new Criteria("item_keywords").is(searchMap.get("keywords"));
query.addCriteria(criteria );
ScoredPage<TbItem> page = solrTemplate.queryForPage(query, TbItem.class);
map.put("rows", page.getContent());*/
// HighlightQuery(接口)是Query(接口)的子接口
//高亮查询对象
HighlightQuery query = new SimpleHighlightQuery();
//设置高亮选项,API 底层是形如【 <em style='color:red'>三星</em>智能手机】
//设置高亮需明确 1.在哪列加高亮 2.前缀的样式 3.后缀的样式
//1.在哪列加高亮 。addField 设置solr 域在查询的哪一列加高亮可以是多个(如item_title,item_category,item_seller...)
HighlightOptions highlightOptions = new HighlightOptions().addField("item_title");
//2.前缀的样式
highlightOptions.setSimplePrefix("<em style='color:red'>");
//3.后缀的样式
highlightOptions.setSimplePostfix("</em>");
//为查询对象设置高亮选项
query.setHighlightOptions(highlightOptions);
//查询关键字
Criteria criteria = new Criteria("item_keywords").is(searchMap.get("keywords"));
query.addCriteria(criteria);
//高亮页对象
HighlightPage<TbItem> page = solrTemplate.queryForHighlightPage(query, TbItem.class);
//高亮入口集合(其实是查询出来得每一条记录)每个高亮记录的入口
List<HighlightEntry<TbItem>> entryList = page.getHighlighted();
for(HighlightEntry<TbItem> entry: entryList) {
//获取高亮列表(需要被高亮的列当前是:item_title)高亮列的个数
List<Highlight> highlights = entry.getHighlights();
//没有程序出错,增加程序健壮性
if(highlights.size() > 0) {
for(Highlight highlight : highlights) {
//solr每个域中可以存储多个<field name="item_keywords" type="text_ik" indexed="true" stored="false" multiValued="true"/>
List<String> snipplets = highlight.getSnipplets();
//没有程序出错,增加程序健壮性
if (snipplets.size() > 0) {
//得到每个域中的每个值如item_title,item_category,item_seller...
for (String everyItem : snipplets) {
//这个item就是page.getContent()对象
TbItem item = entry.getEntity();
item.setTitle(everyItem);
}
}
}
}
}
map.put("rows", page.getContent());
return map;
}
}
/**
* 搜索高亮显示
* @param searchMap
* @return
*/
public Map searchList(Map searchMap) {
Map map = new HashMap();
// HighlightQuery(接口)是Query(接口)的子接口
//构建高亮查询对象
HighlightQuery query = new SimpleHighlightQuery();
//设置高亮选项,API 底层是形如【 <em style='color:red'>三星</em>智能手机】
//设置高亮需明确 1.在哪列加高亮 2.前缀的样式 3.后缀的样式
//1.在哪列加高亮 。addField 设置solr 域在查询的哪一列加高亮可以是多个(如item_title,item_category,item_seller...)
HighlightOptions highlightOptions = new HighlightOptions().addField("item_title");
//2.前缀的样式 ,angualrjs需要过滤器进行转换,其他不用
highlightOptions.setSimplePrefix("<em style='color:red'>");
//3.后缀的样式
highlightOptions.setSimplePostfix("</em>");
//为查询对象设置高亮选项
query.setHighlightOptions(highlightOptions);
//1.1高亮字查询
//构建查询条件:指定域(item_keywords)查询的关键字(item_keywords)
Criteria criteria = new Criteria("item_keywords").is(searchMap.get("keywords"));
query.addCriteria(criteria);
//1.2按商品分类查询
if (!"".equals(searchMap.get("category"))) {
FilterQuery filterQuery = new SimpleFilterQuery();
Criteria filterCriteria = new Criteria("item_category").is(searchMap.get("category"));
filterQuery.addCriteria(filterCriteria );
query.addFilterQuery(filterQuery );
}
//1.3按品牌查询
if (!"".equals(searchMap.get("brand"))) {
FilterQuery filterQuery = new SimpleFilterQuery();
Criteria filterCriteria = new Criteria("item_brand").is(searchMap.get("brand"));
filterQuery.addCriteria(filterCriteria );
query.addFilterQuery(filterQuery );
}
//1.4按规格查询
if (searchMap.get("spec") != null) {
//前段过来的格式是{'网络':'移动4G','内存','128G'}其本身就是个Map,所以不用json转,直接强制转换即可
Map<String, String> specMap = (Map<String, String>) searchMap.get("spec");
for (String key : specMap.keySet()) {
FilterQuery filterQuery = new SimpleFilterQuery();
Criteria filterCriteria = new Criteria("item_spec_"+key).is(specMap.get(key));
filterQuery.addCriteria(filterCriteria );
query.addFilterQuery(filterQuery );
}
}
//1.5按价格查询
if (!"".equals(searchMap.get("price"))) {
String[] price = ((String)searchMap.get("price")).split("-");
//最低价条件查询
if (!"0".equals(price[0])) {//如果最低价格不等0
FilterQuery filterQuery = new SimpleFilterQuery();
Criteria filterCriteria = new Criteria("item_price").greaterThanEqual(price[0]);
filterQuery.addCriteria(filterCriteria);
query.addFilterQuery(filterQuery);
}
//最高价条件查询
if (!"*".equals(price[1])) {//如果最低价格不等0
FilterQuery filterQuery = new SimpleFilterQuery();
Criteria filterCriteria = new Criteria("item_price").lessThanEqual(price[1]);
filterQuery.addCriteria(filterCriteria );
query.addFilterQuery(filterQuery );
}
}
//1.6分页查询
Integer pageNum =(Integer) searchMap.get("pageNo");
if (pageNum == null) {
pageNum =1;
}
Integer pageSize =(Integer) searchMap.get("pageSize");
if (pageSize == null) {
pageSize = 20;
}
//原生的limit分页就可以用这种方式
query.setOffset((pageNum-1)*pageSize);//得到起始页的索引(公式:(页数-1)*页的长度,并不是页数,
query.setRows(pageSize);
//************** 获取高亮结果集 **********
//获取高亮页对象
HighlightPage<TbItem> page = solrTemplate.queryForHighlightPage(query, TbItem.class);
//高亮入口集合(其实是查询出来得每一条记录)每个高亮记录的入口
List<HighlightEntry<TbItem>> entryList = page.getHighlighted();
for(HighlightEntry<TbItem> entry: entryList) {
//获取高亮列表(需要被高亮的列当前是:item_title)高亮列的个数
List<Highlight> highlights = entry.getHighlights();
//没有程序出错,增加程序健壮性
if(highlights.size() > 0) {
for(Highlight highlight : highlights) {
//solr每个域中可以存储多个<field name="item_keywords" type="text_ik" indexed="true" stored="false" multiValued="true"/>
List<String> snipplets = highlight.getSnipplets();
//没有程序出错,增加程序健壮性
if (snipplets.size() > 0) {
//得到每个域中的每个值如item_title,item_category,item_seller...
for (String everyItem : snipplets) {
//这个item就是page.getContent()对象
TbItem item = entry.getEntity();
item.setTitle(everyItem);
}
}
}
}
}
map.put("rows", page.getContent());
//总页数
map.put("totalPages", page.getTotalPages());
//总条数
map.put("total", page.getTotalElements());
return map;
}
Dobux配置请求超时@Service(timeout=5000)
@RequestBody:前台请求是一个对象使用的注解@RequestBody Map searchMap
/**
* 查询商品分类列表(相当于分组查询,但实际不是)
* @param searchMap
* @return
*/
public List<String> searchCategoryList(Map searchMap) {
List<String> list = new ArrayList<String>();
//1.创建查询队象
Query query = new SimpleQuery("*:*");
//2.构建查询条件(添加可能查询的值):(item_keywords(复制域)复制域的好处是可以包含所有查询类型)查询的关键字(item_keywords)
Criteria criteria = new Criteria("item_keywords").is(searchMap.get("keywords"));//相当于sql中的wehere = ?
query.addCriteria(criteria);
//3.构建分组选项(指定查询的域可有多个)
GroupOptions groupOptions = new GroupOptions().addGroupByField("item_category");//相当于sql中的group by XXX
query.setGroupOptions(groupOptions );
//4.得到分组页对象
//执行查询得到分组页对象,【注意】分组页对象也有getContent()方法,但是他的结果是一个空值
//,是因为他父接口Page是有这个方法他必须有这个方法
GroupPage<TbItem> groupPage = solrTemplate.queryForGroupPage(query, TbItem.class);//分组页对象
//5.通过分组页对象得到分页组结果对象
//一个分组对象可以有多个分组结果对象
GroupResult<TbItem> groupResult = groupPage.getGroupResult("item_category");//分组结果对象
//6.分组结果对象得到分组入口页【注意】分页组结果对象是对象,分组页接口页是集合,他们是包含关系,
Page<GroupEntry<TbItem>> groupEntries = groupResult.getGroupEntries();//分组入口页对象
//7.得到所有分组入口页集合
List<GroupEntry<TbItem>> content = groupEntries.getContent();//分组入口集合
//8.得到每一个分组入口
for (GroupEntry<TbItem> groupEntry : content) {
//分组结果添加到返回值中
list.add(groupEntry.getGroupValue());
}
return list;
}