前言
全文检索
于 sql 模糊查询
,最大的区别,在于
① 前者能将要查询的关键字符串先进行灵活分词,再进行匹配,
② 后者只会直接死板匹配。
③ 很多网站都有站内搜索,每个后台的应该会,故做了个 demo 分享
还有很多优点,相信大家都已经了解
摘要
前后端分离
① 前端框架:jQuery、LayUI
② 后台框架:SpringBoot、Solr
模仿百度搜索,麻雀虽小,五脏俱全
本文很多基础都来自笔者之前的文章
① Solr 基础:[增删改查] SpringBoot 整合 Solr 之 SolrClient 实现 CRUD、分页接口、高亮显示
② 前后端分离之跨域问题解决:在 SpringBoot 中设置允许跨域请求
③ LayUI 基础:使用新、热、轻量、简单、强大、优美的 LayUI框架 构建前端页面
效果
gif 图解读:
① 搜索 Java爬虫技术
② 搜索 SpringBoot整合Solr
③ 随便点击搜索结果的一个链接
思考:
若不是使用了 Solr全文检索,则搜索词 Java学习
,因首字母大写、后面还有中文,无法匹配 java爬虫
等。
前端代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ITAEM 搜索</title>
<link rel="stylesheet" href="layui/css/layui.css" />
<script src="js/jquery-1.7.2.js"></script>
<script src="layui/layui.js"></script>
<script type="text/javascript">
</script>
</head>
<body>
<br />
<div class="layui-row layui-col-space3">
<div class="layui-col-md1">
<img src="img/itaem.png" height="30px" />
</div>
<div class="layui-col-md2">
<input type="text" id="query" name="q" required lay-verify="required" placeholder="输入关键字" class="layui-input">
</div>
<div class="layui-col-md1">
<button id="btn2" onclick="upd()" class="layui-btn"> 搜索 </button>
</div>
</div>
<!--横线-->
<hr class="layui-bg-red">
<!--搜索结果-->
<div id="result">
<hr class="layui-bg-gray">
</div>
<div id="page"></div>
<script>
function show(highlight, href) {
//由于为Java集合 的 List 类型、 Array 类型共存,只能这样
var i = 0;
$.each(highlight, function(index, title) {
var a = $("<a></a>").append(title.title[0]).attr("href", href[i].href[0]);
a.attr("target", "_blank");
var bq = $("<blockquote class='layui-elem-quote'>").append(a);
var div = $("<div></div>").append(bq);
$('#result').append("<hr />").append(div)
i++;
});
}
function upd() {
var q = $("#query").val();
$.ajax({
type: "get",
url: "http://localhost/test/select/" + q + "/0/5",
success: function(result) {
$('#result').empty()
var highlight = result.highlight;
var href = result.href;
var total = result.total;
show(highlight, href);
//分页条再次渲染
layui.use('laypage', function() {
//获取页模块
var laypage = layui.laypage;
//执行一个laypage实例
laypage.render({
//注意,这里的 page 是 ID,不用加 # 号
elem: 'page',
//数据总数,从服务端得到
count: total,
//每页的数据量
limit: 5,
//相连页数量
groups: 5
});
});
}
});
}
</script>
</body>
</html>
后台
package com.cun.controller;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.solr.client.solrj.SolrClient;
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.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* 优化:抽取 Id、text 为一个 JavaBean
* @author linhongcun
*
*/
@RestController
@RequestMapping("/test")
@EnableSwagger2
public class SolrController {
@Autowired
private SolrClient client;
/**
* 1、增
* @param message
* @return
* @throws IOException
* @throws SolrServerException
*/
@PostMapping("/insert")
public String insert(String title, String href) throws IOException, SolrServerException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddhhmmss");
String dateString = sdf.format(new Date());
try {
SolrInputDocument doc = new SolrInputDocument();
doc.setField("id", dateString);
doc.setField("title", title);
doc.setField("href", href);
/*
* 如果 spring.data.solr.host 里面配置到 core了, 那么这里就不需要传 collection1 这个参数 下面都是一样的 即
* client.commit();
*/
client.add("itaem", doc);
client.commit("itaem");
return dateString;
} catch (Exception e) {
e.printStackTrace();
}
return "error";
}
/**
* 4、删 all
* @return
*/
@DeleteMapping("deleteAll")
public String deleteAll() {
try {
client.deleteByQuery("itaem", "*:*");
client.commit("itaem");
return "success";
} catch (Exception e) {
e.printStackTrace();
}
return "error";
}
/**
* 7、查 ++:关键字、高亮、分页 ✔
* @return
* @return
* @throws SolrServerException
* @throws IOException
*/
@GetMapping("/select/{q}/{page}/{size}")
public Map<String, Object> select(@PathVariable String q, @PathVariable Integer page, @PathVariable Integer size)
throws SolrServerException, IOException {
SolrQuery params = new SolrQuery();
// 查询条件
params.set("q", q);
// 排序,实际应根据得分,不过也没关系,所有查到的记录都是相关的,不相干的排除了
params.addSort("id", SolrQuery.ORDER.desc);
// 分页
params.setStart(page);
params.setRows(size);
// 默认域
params.set("df", "title");
// 只查询指定域
params.set("fl", "href");
// 开启高亮
params.setHighlight(true);
// 设置前缀
params.setHighlightSimplePre("<span style='color:red'>");
// 设置后缀
params.setHighlightSimplePost("</span>");
// solr数据库是 itaem
QueryResponse queryResponse = client.query("itaem", params);
SolrDocumentList results = queryResponse.getResults();
// 数量,分页用
long total = results.getNumFound();// JS 使用 size=MXA 和 data.length 即可知道长度了(但不合理)
// 获取高亮显示的结果, 高亮显示的结果和查询结果是分开放的
Map<String, Map<String, List<String>>> highlight = queryResponse.getHighlighting();
Map<String, Object> map = new HashMap<String, Object>();
map.put("total", total);
map.put("href", results);
map.put("highlight", highlight);
return map;
}
}