1、前言
配置方面请自行百度,可参考
Windows下搭建ElasticSearch、Logstash以及基本插件
2、搭建springdata项目
注意:这里只给几个重要点的代码,本文最后有网盘链接
(1)pojo
indexName 表示索引名
@Data
@Document(indexName = "goodscat", type = "docs", shards = 1, replicas = 0)
public class Goods {
@Id
private Long cid;
//@Field(type = FieldType.Keyword, index = true, analyzer = "ik_max_word")
//@Field(index = true,type = FieldType.Text,analyzer="ik_max_word",searchAnalyzer="ik_max_word")
private String name;
private String isParent;
private String parentId;
private Long level;
private String pathid;
}
@Data
@Entity(name="wp_ex_source_goods_tb_cat_copy")
public class XcGoods implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "cid")
private Long cid;
@Column(name = "name")
private String name;
@Column(name = "is_parent")
private String isParent;
@Column(name = "parent_id")
private String parentId;
@Column(name = "level")
private Long level;
@Column(name = "pathid")
private String pathid;
@Column(name = "path")
private String path;
}
(2)service
@Slf4j
@Service
public class SearchServiceImpl implements SearchService {
@Autowired
private GoodsRepository goodsRepository;
@Autowired
private ElasticsearchTemplate template;
@Override
public Goods buildGoods(XcGoods xcgoods) {
//搜索字段
// String all = xcgoods.getName();
//构建goods对象
Goods goods = new Goods();
goods.setCid(xcgoods.getCid());
goods.setName(xcgoods.getName());
goods.setIsParent(xcgoods.getIsParent());
goods.setParentId(xcgoods.getParentId());
goods.setPathid(xcgoods.getPathid());
goods.setLevel(xcgoods.getLevel());
// 搜索字段,包含标题,分类,品牌,规格,等等
// goods.setAll(all);
return goods;
}
@Override
public PageResult<Goods> search(SearchRequest request) {
int page = request.getPage() - 1;
int size = request.getSize();
//创建查询构建器
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
//结果过滤
queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{"cid", "name"}, null));
//分页
queryBuilder.withPageable(PageRequest.of(page, size));
//过滤
queryBuilder.withQuery(QueryBuilders.matchQuery("name", request.getKey()));
//查询
Page<Goods> result1 = goodsRepository.search(queryBuilder.build());
AggregatedPage<Goods> result = template.queryForPage(queryBuilder.build(), Goods.class);
//解析结果
//分页结果解析
long total = result.getTotalElements();
Integer totalPages1 = result.getTotalPages(); //失效
Long totalPages = total % size == 0 ? total / size : total / size + 1;
List<Goods> goodsList = result.getContent();
System.out.println(goodsList.size());
//解析聚合结果
return new SearchResult(total, totalPages, goodsList);
}
(3)
@RestController
public class SearchController {
@Autowired
private SearchService searchService;
/**
* 搜索功能
* @param request
* @return
*/
@GetMapping("search")
public ResponseEntity<PageResult<Goods>> search(SearchRequest request) {
return ResponseEntity.ok(searchService.search(request));
}
(4)
运行testCreateIndex()创建索引,注意如果索引名已存在会报错
@SpringBootTest(classes = {SpringdataelasticsearchApplication.class})
public class SearchServiceImplTest {
@Autowired
private GoodsRepository goodsRepository;
@Autowired
private ElasticsearchTemplate template;
@Autowired
private SearchService searchService;
@Autowired
private XcGoodsRepository xcGoodsRepository;
//创建索引
@Test
public void testCreateIndex() {
template.createIndex(Goods.class);
template.putMapping(Goods.class);
}
//加载数据
@Test
public void loadData() {
int page = 1;
int rows = 100;
int size = 0;
//查询spu信息
do {
Page<XcGoods> result = xcGoodsRepository.findAll(PageRequest.of(page - 1, rows));
List<XcGoods> spuList = result.getContent();
if (CollectionUtils.isEmpty(spuList)){
break;
}
//构建成goods
List<Goods> goodsList = spuList.stream()
.map(searchService::buildGoods).collect(Collectors.toList());
//存入索引库
goodsRepository.saveAll(goodsList);
//翻页
page++;
size = spuList.size();
} while (size == 100);
}
}
3、前端使用vue
<template>
<div>
<div class="bookstable">
<el-autocomplete
v-model="state"
:fetch-suggestions="querySearchAsync"
placeholder="请输入内容"
@select="handleSelect"
select-when-unmatched="true"
:debounce="0"
></el-autocomplete>
<el-button slot="append" icon="el-icon-search" @click="onSubmit"></el-button>
<div class="div2" v-show="con">
<p>
搜索
<span style="color: #F08080">{{state}}</span>的结果(总共搜索到
<span style="color: #F08080">{{total}}</span>条记录)
</p>
<p v-for="entity in All" class="p2">
<a href="http://www.baidu.com">{{entity.name}}</a>
</p>
<!--分页组件 -->
<div class="block">
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange"
:page-count="totalPage" :page-sizes="[5, 10, 20, 30]" :page-size="20"
layout="total, sizes, prev, pager, next, jumper"
@prev-click="prePage" @next-click="nextPage" :total="total" :current-page="page">
</el-pagination>
</div>
</div>
</div>
</div>
</template>
<script>
const axios = require('axios')
export default {
name: 'HelloWorld',
data () {
return {
state: '',
con: false,
restaurants: [],
All: [],
timeout: null,
page: 1, //分页默认
rows: 20, //每页数量
total: 0,//总页数
totalPage: 5, //总页数
pageSizes: {
default () {
return [5, 10, 20, 30]
}
},
}
},
watch: {//监控一个值的变换
state: { // 监视字段,页数
handler () {
if (this.state.length > 0) {
this.loadAll()
} else {
this.con = false
this.restaurants = []
this.All = []
this.page = 1
}
}
},
page: { // 监视字段,页数
handler () {
this.loadAll()
}
}
}, methods: {//提供存放方法的地方
nextPage () {
if (this.page < this.totalPage) this.page++
},
prePage () {
if (this.page > 1) this.page--
},
selectPage (i) {
this.page = i //修改当前页
},
handleSizeChange (val) {
this.rows = val
console.log(`每页 ${val} 条`)
},
handleCurrentChange (val) {
this.page = val
console.log(`当前页: ${val}`)
},
loadAll (h) {
var app = this
var a = h == undefined ? app : h
axios.get('search', {
params: {
'page': this.page,
'key': this.state,
}
})
.then(response => {
this.total = response.data.total
this.totalPage = response.data.totalPages
var rs = response.data.items
app.All = rs
//在这里为这个数组中每一个对象加一个value字段, 因为autocomplete只识别value字段并在下拉列中显示
for (let i of app.All) {
i.value = i.name //将想要展示的数据作为value
}
app.restaurants = response.data.items
console.log('response', app.restaurants)
})
.catch(function (error) {
// handle error
console.log(error)
})
},
querySearchAsync (queryString, cb) {
var restaurants = this.restaurants
var results = queryString ? restaurants.filter(this.createStateFilter(queryString)) : restaurants
clearTimeout(this.timeout)
this.timeout = setTimeout(() => {
cb(results)
}, 3000 * Math.random())
},
createStateFilter (queryString) {
return (state) => {
return (state.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0)
}
},
handleSelect (item) {
this.con = true
console.log(item)
},
onSubmit () {
this.con = true
}
}
}
</script>
<style>
.el-autocomplete {
width: 400px;
}
.p2 {
margin-left: 100px;
text-align: left;
font-size: 20px;
color: blue;
}
.div2 {
/* background: blue; */
margin-top: 25px;
padding-top: 25px;
margin-left: 270px;
width: 750px;
height: 650px;
}
</style>
运行效果如下
后台代码
链接:https://pan.baidu.com/s/1TT0KX6hB3svvamdMaJwBwA
提取码:e0xq