zoukankan      html  css  js  c++  java
  • SolrJ 复杂查询 高亮显示

    SolrJ 复杂查询 高亮显示

    上一章搭建了Solr服务器和导入了商品数据,本章通过SolrJ去学习Solr在企业中的运用。笔者最先是通过公司的云客服系统接触的Solr,几百万的留言秒秒钟就查询并高亮显示,不同的广告员还可以只检索自己所属国家的留言。瞬间就跪拜在Solr的石榴裙下。现在看来其实就是 q + fq + lg 的用法。通过本章内容你将会学习到Solr分词配置;SolrJ的复杂查询和关键字高亮语法;Solr各版本之间SolrJ的语法差异;Solr7与Spring的整合等使用技能。

    需求:搜索栏输入关键字全文检索商品,选择类目或价格区间筛选商品,选择价格排序商品。
    技术:SolrJ,Spring,SpringMVC
    说明:通过本章内容你将会学习到Solr分词配置;SolrJ的复杂查询和关键字高亮语法;Solr各版本之间SolrJ的语法差异;Solr7与Spring的整合;搜索商品开发思路;本教程页面来源网络,笔者做了简单的修改,仅供学习使用。关注文章底部微信公众号领红包哦!
    源码:见文章底部
    项目结构:
    项目结构

    效果图:
    效果图

    Solr分词配置

    solr7 安装部署:http://www.cnblogs.com/itdragon/p/7995040.html

    [tomtop926@localhost lib]$ll IK*
    -rw-rw-r--. 1 tomtop926 tomtop926 1165908 Dec  6 15:06 IKAnalyzer2012FF_u1.jar
    [tomtop926@localhost lib]$cd ../classes/
    [tomtop926@localhost classes]$ll
    total 16
    -rw-rw-r--. 1 tomtop926 tomtop926  168 Dec  6 15:08 ext_stopword.dic
    -rw-rw-r--. 1 tomtop926 tomtop926  419 Dec  6 15:07 IKAnalyzer.cfg.xml
    -rw-r--r--. 1 tomtop926 tomtop926 1421 Dec  5 12:09 log4j.properties
    -rw-rw-r--. 1 tomtop926 tomtop926   12 Dec  6 15:08 mydict.dic
    [tomtop926@localhost classes]$cd 
    [tomtop926@localhost ~]$vim solr/apache-tomcat-8.5/solrhome/new_core/conf/managed-schema
    <fieldType name="text_ik" class="solr.TextField">
      <analyzer type="index">
        <tokenizer class="org.apache.lucene.analysis.ik.IKTokenizerFactory" useSmart="true"/>
      </analyzer>
      <analyzer type="query">
        <tokenizer class="org.apache.lucene.analysis.ik.IKTokenizerFactory" useSmart="true"/>
      </analyzer>
    </fieldType>
    ......
    <field name="product_catalog" type="string" indexed="true" stored="true"/>
    <field name="product_catalog_name" type="string" indexed="true" stored="true"/>
    <field name="product_description" type="text_ik" indexed="true" stored="false"/>
    <field name="product_name" type="text_ik" indexed="true" stored="true"/>
    <field name="product_picture" type="string" indexed="false" stored="true"/>
    <field name="product_price" type="pfloat" indexed="true" stored="true"/>
    <field name="product_keywords" type="text_ik" multiValued="true" indexed="true" stored="false"/>
    <copyField source="product_description" dest="product_keywords"/>
    <copyField source="product_name" dest="product_keywords"/>
    

    第一步:将IKAnalyzer2012.jar导入到tomcat/webapps/solr/WEB-INF/lib目录下
    第二步:将ext_stopword.dic(停用词词典),IKAnalyzer.cfg.xml(配置文件),mydict.dic(自定义词典) 导入到tomcat/webapps/solr/WEB-INF/classes
    第三步:编辑managed-schema 文件,配置中文分析器
    第四步:并配置业务域(solr字段),给product_description,product_name设置中文分词并放在product_keywords目标域中。下一章会重点介绍schema文件。

    SolrJ 单元测试

    在采用Solr实现全文检索功能时,我们需对Solr的java客户端SolrJ语法有一定的了解。这里创建 SolrJTest.java 类测试SolrJ的连接,查询,过滤,排序,分页,高亮等功能,以及索引的维护。

    package com.itdragon.test;
    
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import org.apache.solr.client.solrj.SolrQuery;
    import org.apache.solr.client.solrj.SolrQuery.ORDER;
    import org.apache.solr.client.solrj.SolrServerException;
    import org.apache.solr.client.solrj.impl.HttpSolrClient;
    import org.apache.solr.client.solrj.response.QueryResponse;
    import org.apache.solr.common.SolrDocument;
    import org.apache.solr.common.SolrDocumentList;
    import org.apache.solr.common.SolrInputDocument;
    import org.apache.solr.common.params.MapSolrParams;
    import org.junit.Test;
    
    public class SolrJTest {
    	
    	/**
    	 * 不同Solr 版本之间创建连接方式不同
    	 * Solr4 : SolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr");  
    	 * Solr5 :HttpSolrClient solrClient = new HttpSolrClient("http://localhost:8080/solr/new_core");
    	 * Solr7 :HttpSolrClient solrClient = new HttpSolrClient.Builder("http://localhost:8080/solr/new_core").build();
    	 * 
    	 * SolrQuery 对应的api接口
    	 * q : setQuery
    	 * fq : addFilterQuery
    	 * sort : setSort
    	 * start : setStart(0);
    	 * rows : setRows(10);
    	 * fl : setFields
    	 * 
    	 */
    	
    	private final static String BASE_SOLR_URL = "http://localhost:8080/solr/new_core";
    	
    	// solrJ 基础用法
    	@Test
    	public void queryDocumentBasic() throws Exception {
    		// 创建连接
    		HttpSolrClient solrClient = new HttpSolrClient.Builder(BASE_SOLR_URL).build();
    		
    		/* 不推荐
    		Map<String, String> queryParamMap = new HashMap<String, String>();
    		// 封装查询参数
    		queryParamMap.put("q", "*:*");
            // 添加到SolrParams对象
            MapSolrParams query = new MapSolrParams(queryParamMap);
            */
    		
    		// 设置查询条件
            SolrQuery query = new SolrQuery();
    		query.setQuery("*:*");
            // 执行查询
            QueryResponse response = solrClient.query(query);
            // 获取doc文档
            SolrDocumentList documents = response.getResults();
    		System.out.println("共查询到记录:" + documents.getNumFound());
    		for (SolrDocument solrDocument : documents) {
    			System.out.println("ID : " + solrDocument.get("id") + " 	 Name : " + solrDocument.get("product_name"));
    		}
    	}
    	
    	// solrJ 的复杂查询
    	@Test
    	public void queryDocument() throws Exception {
    		// 创建连接
    		HttpSolrClient solrClient = new HttpSolrClient.Builder(BASE_SOLR_URL).build();
    		SolrQuery query = new SolrQuery();
    		// 设置查询条件
    		query.setQuery("product_name:街头原木电话亭");
    		// 设置分页信息
    		query.setStart(0);
    		query.setRows(10);
    		// 设置排序
    		query.setSort("id", ORDER.desc);
    		// 设置显示的Field的域集合,即设置那些值有返回值
    		query.setFields("id,product_name");
    		// 设置默认域
    		query.set("df", "product_keywords");
    		// 设置高亮信息
    		query.setHighlight(true);
    		query.addHighlightField("product_name");
    		query.setHighlightSimplePre("<em>");
    		query.setHighlightSimplePost("</em>");
    		// 执行查询
    		QueryResponse response = solrClient.query(query);
    		// 获取doc文档
    		SolrDocumentList documents = response.getResults();
    		System.out.println("共查询到记录:" + documents.getNumFound());
    		// 获取高亮显示信息
    		Map<String, Map<String, List<String>>> highlighting = response.getHighlighting();
    		for (SolrDocument doc : documents) {
    			System.out.println(doc.get("id"));
    			List<String> hightDocs = highlighting.get(doc.get("id")).get("product_name");
    			if (hightDocs != null)
    				System.out.println("高亮显示的商品名称:" + hightDocs.get(0));
    			else {
    				System.out.println(doc.get("product_name"));
    			}
    		}
    	}
    	
    	// 添加索引
    	@Test
    	public void addDocuments() throws SolrServerException, IOException {
    		HttpSolrClient solrClient = new HttpSolrClient.Builder(BASE_SOLR_URL).withConnectionTimeout(10000)
                    .withSocketTimeout(60000).build();
    		// 创建一个文档对象
    		SolrInputDocument document = new SolrInputDocument();
    		document.addField("id", "add-001");
    		document.addField("product_name", "ITDragon-Solr7系列博客");
    		// 将文档对象写入到索引库中
    		solrClient.add(document);
    		// 提交
    		solrClient.commit();
    	}
    	
    	// 更新的逻辑:先通过id将直接的数据删掉,然后再创建,所以update 和 create 是同一代码
    	
    	// 删除/批量删除索引
    	@Test
    	public void deleteDocument() throws SolrServerException, IOException {
    		HttpSolrClient solrClient = new HttpSolrClient.Builder(BASE_SOLR_URL).build();
    		//solrClient.deleteById("add-001"); 通过id删除
    		/* 批量删除
    		ArrayList<String> ids = new ArrayList<String>();
            ids.add("1");
            ids.add("2");
            solrClient.deleteById(ids);
            */
    		solrClient.deleteByQuery("id:add-001"); // 通过查询条件删除
    		solrClient.commit();
    	}
    	
    }
    

    SolrJ Web项目

    项目构建思路

    单元测试通过后,说明核心技术已经掌握,现在开始搭建web项目实现需求。通过Maven 搭建MVC web项目。
    第一步:导入SolrJ的jar包,新增用于方便管理 Spring整合Solr的 xml文件。
    第二步:创建商品Product实体类。为了方便前端分页显示,将查询的商品实体类集合,查询的商品总数,总页数,当前页封装到实体类SearchProductResult中。
    第三步:为了方便管理SolrJ核心方法。创建SolrSearchDao接口,并实现查询接口,传入的参数是SolrQuery,不添加任何业务逻辑。
    第四步:创建用于处理业务的ProductService接口,并实现高可用查询接口。负责拼接查询条件实现业务逻辑。
    第五步:为了提高ProductService 查询接口的可用性,新增枚举类FilterQueryKey,管理复杂查询的key。
    第六步:Controller层新增ProductController类,负责接收,返回参数并跳转页面。
    第七步:页面展示,通过c:forEach 遍历查询结果,fmt:formatNumber格式化价格,以及负责查询的form表单。

    配置文件

    Maven 项目核心文件 pom.xml ,导入solrj jar,Solr7对应的SolrJ版本是 7.1.0

    <dependency>
    	<groupId>org.apache.solr</groupId>
    	<artifactId>solr-solrj</artifactId>
    	<version>7.1.0</version>
    </dependency>
    

    Spring 整合Solr 配置文件 applicationContext-solr.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
    	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
    	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
    	http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
    
    	<!-- 配置SolrServer对象 -->
    	<!-- 单机版 -->
    	<bean id="httpSolrClient" class="org.apache.solr.client.solrj.impl.HttpSolrClient">
    	    <constructor-arg name="builder" value="${SOLR.SERVER.URL}"/>
    	</bean>
    	 
    	<bean id="solrSearchDaoImpl" class="com.itdragon.solr.service.impl.SolrSearchDaoImpl" />
    </beans>
    

    资源文件 resource.properties

    SOLR.SERVER.URL=http://localhost:8080/solr/new_core
    

    实体类

    这里有三个文件,一个是商品类 Product.java ,一个是返回参数封装类 SearchProductResult.java ,一个是管理查询key的枚举类FilterQueryKey.java

    package com.itdragon.mapper.pojo;
    
    import org.apache.solr.client.solrj.beans.Field;
    
    public class Product {
        
        @Field
        private String id;				// 商品编号
        @Field
        private String name; 			// 商品名称
        @Field
        private String catalog_name; 	// 商品分类名称
        @Field
        private Float price;			// 价格
        @Field
        private Long number;			// 数量
        @Field
        private String picture;			//图片名称
        @Field
        private String description;		// 商品描述
    
        // get,set 方法省略
    
    }
    
    import java.util.List;
    
    public class SearchProductResult {
    
    	private List<Product> productList;	// 商品列表
    	private Long recordCount;	// 商品总数
    	private Integer pageCount;	// 总页数
    	private Integer curPage;	// 当前页
    
    	// get,set 方法省略
    
    }
    
    package com.itdragon.mapper.pojo;
    
    public enum FilterQueryKey {
    	
    	PRICE("price"), // 价格
    	CATALOG_NAME("catalog_name"), // 类目名
    	SORT("sort"); // 价格排序
    	
    	private String value;
    
    	private FilterQueryKey(String value) {
    		this.value = value;
    	}
    
    	public String getValue() {
    		return value;
    	}
    
    	public static FilterQueryKey fromValue(String v) {
            for (FilterQueryKey c: FilterQueryKey.values()) {
                if (c.value.equals(v)) {
                    return c;
                }
            }
            throw new IllegalArgumentException(v);
        }
    
    }
    

    Dao 层

    提供了SolrJ的查询接口及其实现类 SolrSearchDaoImpl.java ,这里不要有任何业务相关的代码。这里需要注意关键词高亮显示。在Solr管理页面分析高亮返回的机构,以方便获取对应的值。
    高亮的结构

    package com.itdragon.solr.service.impl;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    import org.apache.commons.collections.CollectionUtils;
    import org.apache.solr.client.solrj.SolrQuery;
    import org.apache.solr.client.solrj.impl.HttpSolrClient;
    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 com.itdragon.mapper.pojo.Product;
    import com.itdragon.mapper.pojo.SearchProductResult;
    import com.itdragon.solr.service.SolrSearchDao;
    
    public class SolrSearchDaoImpl implements SolrSearchDao {
    	
    	@Autowired
    	private HttpSolrClient httpSolrClient;
    
    	@Override
    	public SearchProductResult search(SolrQuery query) throws Exception {
    		// 返回值对象
    		SearchProductResult result = new SearchProductResult();
    		// 根据查询条件查询索引库
    		System.out.println("solr Query : " + query);
    		QueryResponse queryResponse = httpSolrClient.query(query);
    		// 获取查询结果
    		SolrDocumentList solrDocumentList = queryResponse.getResults();
    		// 获取查询结果总数量
    		result.setRecordCount(solrDocumentList.getNumFound());
    		// 初始化返回结果商品列表
    		List<Product> products = new ArrayList<>();
    		// 获取高亮显示数据
    		Map<String, Map<String, List<String>>> highlighting = queryResponse.getHighlighting();
    		// 遍历查询结果
    		for (SolrDocument solrDocument : solrDocumentList) {
    			Product product = new Product();
    			product.setId((String) solrDocument.get("id"));
    			// 获取高亮显示的集合
    			List<String> hightNames = highlighting.get(solrDocument.get("id")).get("product_name");
    			String pName = CollectionUtils.isNotEmpty(hightNames)? hightNames.get(0) : (String) solrDocument.get("product_name");
    			product.setName(pName);
    			product.setPicture((String) solrDocument.get("product_picture"));
    			product.setPrice((float) solrDocument.get("product_price"));
    			product.setCatalog_name((String) solrDocument.get("product_category_name"));
    			products.add(product);
    		}
    		result.setProductList(products);
    		return result;
    	}
    
    }
    

    Service 层

    提供了根据业务需求逻辑查询商品的接口及其实现类 ProductServiceImpl.java

    package com.itdragon.service.impl;
    
    import java.util.Map;
    import org.apache.commons.lang3.StringUtils;
    import org.apache.solr.client.solrj.SolrQuery;
    import org.apache.solr.client.solrj.SolrQuery.ORDER;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import com.itdragon.mapper.pojo.FilterQueryKey;
    import com.itdragon.mapper.pojo.SearchProductResult;
    import com.itdragon.service.ProductService;
    import com.itdragon.solr.service.SolrSearchDao;
    
    @Service
    public class ProductServiceImpl implements ProductService {
    	
    	@Autowired
    	private SolrSearchDao solrSearchDao;
    
    	@Override
    	public SearchProductResult search(String queryString, Map<String, String> filterQueryMap, Integer page, Integer rows) throws Exception {
    		// 创建查询对象
    		SolrQuery query = new SolrQuery();
    		// 设置查询条件
    		queryString = StringUtils.isEmpty(queryString)? "*:*" : queryString;
    		query.setQuery(queryString);
    		// 设置复杂查询条件
    		if (null != filterQueryMap.get(FilterQueryKey.CATALOG_NAME.getValue())) {
    			query.addFilterQuery("product_catalog_name:" + filterQueryMap.get(FilterQueryKey.CATALOG_NAME.getValue()));
    		}
    		if (null != filterQueryMap.get(FilterQueryKey.PRICE.getValue())) {
    			String price = filterQueryMap.get(FilterQueryKey.PRICE.getValue());
    			query.addFilterQuery("product_price:[" + price.split("-")[0] + " TO " + price.split("-")[1] + "]");
    		}
    		if (null != filterQueryMap.get(FilterQueryKey.SORT.getValue())) {
    			String priceSort = filterQueryMap.get(FilterQueryKey.SORT.getValue());
    			query.setSort("product_price", "1".equals(priceSort) ? ORDER.desc : ORDER.asc);
    		}
    		// 设置分页
    		query.setStart((page - 1) * rows); // 当前页面开始下标
    		query.setRows(rows);
    		// 设置默认搜素域
    		query.set("df", "product_keywords");
    		// 设置高亮显示
    		query.setHighlight(true);
    		query.addHighlightField("product_name");
    		query.setHighlightSimplePre("<em style="color:red">");
    		query.setHighlightSimplePost("</em>");
    		// 执行查询
    		SearchProductResult searchResult = solrSearchDao.search(query);
    		// 计算查询结果总页数
    		long recordCount = searchResult.getRecordCount();
    		int pageCount = (int) (recordCount % rows > 0? (recordCount / rows) + 1 : (recordCount / rows));
    		searchResult.setPageCount(pageCount);
    		searchResult.setCurPage(page);
    		
    		return searchResult;
    	}
    
    }
    

    Controller 层

    实现主页初始化和检索功能

    package com.itdragon.controller;
    
    import java.util.HashMap;
    import java.util.Map;
    
    import org.apache.commons.lang3.StringUtils;
    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.RequestParam;
    import com.itdragon.mapper.pojo.FilterQueryKey;
    import com.itdragon.mapper.pojo.SearchProductResult;
    import com.itdragon.service.ProductService;
    
    @Controller
    public class ProductController {
    	
    	@Autowired
    	private ProductService searchService;
    	
    	@RequestMapping("/")
    	public String showIndex(Model model) {
    		SearchProductResult searchResult;
    		try {
    			searchResult = searchService.search("*:*", new HashMap<>(), 1, 12);
    			model.addAttribute("result", searchResult);
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		return "index";
    	}
    	
    	@RequestMapping(value="/query")
    	public String search(@RequestParam("queryString")String query, 
    			@RequestParam("catalog_name") String catalog_name, 
    			@RequestParam("price") String price,
    			@RequestParam("sort") String sort,
    			@RequestParam(defaultValue="1")Integer page, 
    			@RequestParam(defaultValue="12")Integer rows, Model model) {
    		SearchProductResult searchResult = null;
    		try {
    			// 拼接复杂的查询语句
    			Map<String, String> filterQueryMap = new HashMap<>();
    			if (StringUtils.isNotBlank(catalog_name)) {
    				filterQueryMap.put(FilterQueryKey.CATALOG_NAME.getValue(), catalog_name);
    			}
    			if (StringUtils.isNotBlank(price)) {
    				filterQueryMap.put(FilterQueryKey.PRICE.getValue(), price);
    			}
    			if (StringUtils.isNotBlank(sort)) {
    				filterQueryMap.put(FilterQueryKey.SORT.getValue(), sort);
    			}
    			searchResult = searchService.search(query, filterQueryMap, page, rows);
    			model.addAttribute("result", searchResult);
    			model.addAttribute("queryString", query);
    			model.addAttribute("catalog_name", catalog_name);
    			model.addAttribute("price", price);
    			model.addAttribute("sort", sort);
    			model.addAttribute("page", page);
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		return "index";	
    	}
    
    }
    

    View 层

    实现点击搜索框进行查询,点击类目筛选查询,点击价格区间查询,点击价格排序,查询结果回显,分页的功能。

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
    <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
    ......省略
    <script type="text/javascript">
    	// 关键字查询
    	function query() {
    		//执行关键词查询时清空过滤条件
    		document.getElementById("catalog_name").value="";
    		document.getElementById("price").value="";
    		document.getElementById("page").value="";
    		queryList();
    	}
    	// 表单提交
    	function queryList() {
    		document.getElementById("actionForm").submit();
    	}
    	// 特殊值查询
    	function filter(key, value) {
    		document.getElementById(key).value=value;
    		queryList();
    	}
    	// 排序
    	function sort() {
    		var s = document.getElementById("sort").value;
    		if (s != "1") {
    			s = "1";
    		} else {
    			s = "0";
    		}
    		document.getElementById("sort").value = s;
    		queryList();
    	}
    	// 翻页
    	function changePage(p) {
    		var curpage = Number(document.getElementById("page").value);
    		curpage = curpage + p;
    		document.getElementById("page").value = curpage;
    		queryList();
    	}
    </script>
    </head>
    <body class="root61">
    ......省略
    <div id="o-header-2013">
    	<div class="w" id="header-2013">
    		<div id="logo-2013" class="ld"><a href="#" hidefocus="true"><b></b><img src="" width="270" height="60" alt="Logo"></a></div>
    		<!--logo end-->
    		<div id="search-2013">
    			<div class="i-search ld">
    				<ul id="shelper" class="hide"></ul>
    				<form id="actionForm" action="/query" method="POST">
    				<div class="form">
    					<input type="text" class="text" accesskey="s" name="queryString" id="key" value="${queryString}"
    						autocomplete="off" onkeydown="javascript:if(event.keyCode==13) {query()}">
    					<input type="button" value="搜索" class="button" onclick="query()">
    				</div>
    				<input type="hidden" name="catalog_name" id="catalog_name" value="${catalog_name}"/> 
    				<input type="hidden" name="price" id="price" value="${price}"/> 
    				<input type="hidden" name="page" id="page" value="${result.curPage}"/> 
    				<input type="hidden" name="sort" id="sort" value="${sort}"/> 
    				</form>
    			</div>
    			<div id="hotwords"></div>
    		</div>
    		<!--search end-->
    	</div>
    	<!--header end-->
    	......省略
    </div>
    <div class="w">
    	<div class="breadcrumb">
    		<strong><a href="#">服饰内衣</a></strong><span>&nbsp;&gt;&nbsp;<a href="#">女装</a>&nbsp;&gt;&nbsp;<a href="#">T恤</a></span>
    	</div>
    </div>
    <div class="w main">
    <div class="right-extra">
    <div id="select" clstag="thirdtype|keycount|thirdtype|select" class="m">
    	<div class="mt">
    		<h1>T恤 -<strong>&nbsp;商品筛选</strong></h1>
    	</div>
    	<!-- 类目查询和价格区间查询 -->
    	<div class="mc attrs">
    		<div data-id="100001" class="brand-attr">
    			<div class="attr">
    				<div class="a-key">商品类别:</div>
    				<div class="a-values">
    					<div class="v-tabs">
    						<div class="tabcon">
    							<div><a href="javascript:filter('catalog_name', '幽默杂货')">幽默杂货</a></div>
    							<div><a href="javascript:filter('catalog_name', '时尚卫浴')">时尚卫浴</a></div>
    							<div><a href="javascript:filter('catalog_name', '另类文体')">另类文体</a></div>
    							<div><a href="javascript:filter('catalog_name', '创意相架')">创意相架</a></div>
    							<div><a href="javascript:filter('catalog_name', '巧妙收纳')">巧妙收纳</a></div>
    						</div>
    					</div>
    				</div>
    			</div>
    		</div>
    		<div data-id="100002" class="prop-attrs">
    			<div class="attr">
    				<div class="a-key">价格:</div>
    				<div class="a-values">
    					<div class="v-fold">
    						<ul class="f-list">
    							<li><a href="javascript:filter('price','0-9')">0-9</a></li>
    							<li><a href="javascript:filter('price','10-29')">10-29</a></li>
    							<li><a href="javascript:filter('price','30-49')">30-49</a></li>
    							<li><a href="javascript:filter('price','50-*')">50以上</a></li>
    						</ul>
    					</div>
    				</div>
    			</div>
    		</div>
    	</div>
    </div>
    <!-- 价格排序,分页 -->
    <div id="filter">
    	<div class="cls"></div>
    	<div class="fore1">
    		<dl class="order">
    			<dt>排序:</dt>
    			<dd><a href="javascript:sort()">价格</a><b></b></dd>
    		</dl>
    		<dl class="activity">
    			<dd></dd>
    		</dl>
    		<div class="pagin pagin-m">
    			<span class="text"><i>${result.curPage }</i>/${result.pageCount }</span>
    			<a href="javascript:changePage(-1)" class="prev">上一页<b></b></a>
    			<a href="javascript:changePage(1)" class="next">下一页<b></b></a>
    		</div>
    		<div class="total">
    			<span>共<strong>${result.recordCount }</strong>个商品
    			</span>
    		</div>
    		<span class="clr"></span>
    	</div>
    </div>
    <!--核心代码,商品列表开始-->
    <div id="plist" class="m plist-n7 plist-n8 prebuy">
    	<ul class="list-h">
    		<c:forEach var="item" items="${result.productList }">
    		<li pid="${item.id }">
    			<div class="lh-wrap">
    				<div class="p-img">
    					<a target="_blank" href="#">
    						<img width="220" height="282" class="err-product" src="/images/${item.picture}">
    					</a>
    				</div>
    				<div class="p-name">
    					<a target="_blank" href="#">${item.name }</a>
    				</div>
    				<div class="p-price">
    					<strong>¥<fmt:formatNumber value="${item.price}" maxFractionDigits="2"/>
    				</div>
    			</div>
    		</li>
    		</c:forEach>
    	</ul>
    </div>
    ......省略
    </body>
    </html>
    

    总结

    • SolrJ连接solr全文检索服务器,实现查询,拦截,排序,分页,高亮等功能。
    • Spring整合SolrJ实现电商商品页面检索,筛选,分页功能。

    源码:https://github.com/ITDragonBlog/daydayup/tree/master/Solr/ssm-solr

    到这里SolrJ 复杂查询 高亮显示就结束了。有什么不对的地方请指出,最后感谢阅读!如果觉得文章不错,麻烦点一下"推荐"

  • 相关阅读:
    DHCP和NAT
    Mongos WoW
    是否能在构造函数,析构函数中抛出异常?
    Lua Getter/Setter
    xLua
    基于模板特化的Lua自动绑定系统
    为什么有人说富坚义博有着殿堂级的画功?他的画功体现在哪儿呢? 关注者 10205 被浏览 2701670
    在Windows和MacOS下编译Lua
    解决warning MSB8012:问题
    setjmp和longjmp
  • 原文地址:https://www.cnblogs.com/itdragon/p/8007144.html
Copyright © 2011-2022 走看看