1. ES继承SpringBoot
自学一门技术首先去官方文档找资料。
一般使用高级客户端的文档:7.6的文档传送门
1.1 获取ESmaven依赖
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.6.2</version>
</dependency>
1.2 构建对象
1.3 搭建项目
创建一个空项目将Es项目相关的操作放在该目录下
新建模块,建立一个springboot项目
选中默认模块
选中web模块
选中Elastcisearch模块
项目环境配置:空项目需要设置自己的编译环境1.8,jdk8,项目的javascript改为ECMAScript6
版本问题不一致时的解决,在pom文件中自定义版本
<properties>
<java.version>1.8</java.version>
<!--如果ES版本依赖过低,需要保证与自己本地下载的版本一致-->
<!--<elasticsearch.version>7.6.2</elasticsearch.version>-->
</properties>
1.4 查看类中的方法
核心类:
上面的三个类都是静态的内部类,ES7.6.1中是RestClientConfigurations类中,个人使用的ES7.6.2,以上的三个类在ElasticsearchRestClientConfigurations类中
class ElasticsearchRestClientConfigurations {
ElasticsearchRestClientConfigurations() {
}
private static class PropertiesCredentialsProvider extends BasicCredentialsProvider {
PropertiesCredentialsProvider(ElasticsearchRestClientProperties properties) {
if (StringUtils.hasText(properties.getUsername())) {
Credentials credentials = new UsernamePasswordCredentials(properties.getUsername(), properties.getPassword());
this.setCredentials(AuthScope.ANY, credentials);
}
properties.getUris().stream().map(this::toUri).filter(this::hasUserInfo).forEach(this::addUserInfoCredentials);
}
private URI toUri(String uri) {
try {
return URI.create(uri);
} catch (IllegalArgumentException var3) {
return null;
}
}
private boolean hasUserInfo(URI uri) {
return uri != null && StringUtils.hasLength(uri.getUserInfo());
}
private void addUserInfoCredentials(URI uri) {
AuthScope authScope = new AuthScope(uri.getHost(), uri.getPort());
Credentials credentials = this.createUserInfoCredentials(uri.getUserInfo());
this.setCredentials(authScope, credentials);
}
private Credentials createUserInfoCredentials(String userInfo) {
int delimiter = userInfo.indexOf(":");
if (delimiter == -1) {
return new UsernamePasswordCredentials(userInfo, (String)null);
} else {
String username = userInfo.substring(0, delimiter);
String password = userInfo.substring(delimiter + 1);
return new UsernamePasswordCredentials(username, password);
}
}
}
//默认的Rest客户端
static class DefaultRestClientBuilderCustomizer implements RestClientBuilderCustomizer {
private static final PropertyMapper map = PropertyMapper.get();
private final ElasticsearchRestClientProperties properties;
DefaultRestClientBuilderCustomizer(ElasticsearchRestClientProperties properties) {
this.properties = properties;
}
public void customize(RestClientBuilder builder) {
}
public void customize(HttpAsyncClientBuilder builder) {
builder.setDefaultCredentialsProvider(new ElasticsearchRestClientConfigurations.PropertiesCredentialsProvider(this.properties));
}
public void customize(Builder builder) {
PropertyMapper var10000 = map;
ElasticsearchRestClientProperties var10001 = this.properties;
this.properties.getClass();
var10000.from(var10001::getConnectionTimeout).whenNonNull().asInt(Duration::toMillis).to(builder::setConnectTimeout);
var10000 = map;
var10001 = this.properties;
this.properties.getClass();
var10000.from(var10001::getReadTimeout).whenNonNull().asInt(Duration::toMillis).to(builder::setSocketTimeout);
}
}
@Configuration(
proxyBeanMethods = false
)
//失败回调静态内部类
static class RestClientFallbackConfiguration {
RestClientFallbackConfiguration() {
}
@Bean
@ConditionalOnMissingBean
RestClient elasticsearchRestClient(RestClientBuilder builder) {
return builder.build();
}
}
@Configuration(
proxyBeanMethods = false
)
//Rest高水平的客户端配置
@ConditionalOnClass({RestHighLevelClient.class})
static class RestHighLevelClientConfiguration {
RestHighLevelClientConfiguration() {
}
@Bean
@ConditionalOnMissingBean
RestHighLevelClient elasticsearchRestHighLevelClient(RestClientBuilder restClientBuilder) {
return new RestHighLevelClient(restClientBuilder);
}
@Bean
@ConditionalOnMissingBean
RestClient elasticsearchRestClient(RestClientBuilder builder, ObjectProvider<RestHighLevelClient> restHighLevelClient) {
RestHighLevelClient client = (RestHighLevelClient)restHighLevelClient.getIfUnique();
return client != null ? client.getLowLevelClient() : builder.build();
}
}
//Rest构建的配置文件,配置端口、连接时间、超时时间等信息
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnMissingBean({RestClientBuilder.class})
static class RestClientBuilderConfiguration {
RestClientBuilderConfiguration() {
}
@Bean
RestClientBuilderCustomizer defaultRestClientBuilderCustomizer(ElasticsearchRestClientProperties properties) {
return new ElasticsearchRestClientConfigurations.DefaultRestClientBuilderCustomizer(properties);
}
@Bean
RestClientBuilder elasticsearchRestClientBuilder(ElasticsearchRestClientProperties properties, ObjectProvider<RestClientBuilderCustomizer> builderCustomizers) {
HttpHost[] hosts = (HttpHost[])properties.getUris().stream().map(this::createHttpHost).toArray((x$0) -> {
return new HttpHost[x$0];
});
RestClientBuilder builder = RestClient.builder(hosts);
builder.setHttpClientConfigCallback((httpClientBuilder) -> {
builderCustomizers.orderedStream().forEach((customizer) -> {
customizer.customize(httpClientBuilder);
});
return httpClientBuilder;
});
builder.setRequestConfigCallback((requestConfigBuilder) -> {
builderCustomizers.orderedStream().forEach((customizer) -> {
customizer.customize(requestConfigBuilder);
});
return requestConfigBuilder;
});
builderCustomizers.orderedStream().forEach((customizer) -> {
customizer.customize(builder);
});
return builder;
}
private HttpHost createHttpHost(String uri) {
try {
return this.createHttpHost(URI.create(uri));
} catch (IllegalArgumentException var3) {
return HttpHost.create(uri);
}
}
private HttpHost createHttpHost(URI uri) {
if (!StringUtils.hasLength(uri.getUserInfo())) {
return HttpHost.create(uri.toString());
} else {
try {
return HttpHost.create((new URI(uri.getScheme(), (String)null, uri.getHost(), uri.getPort(), uri.getPath(), uri.getQuery(), uri.getFragment())).toString());
} catch (URISyntaxException var3) {
throw new IllegalStateException(var3);
}
}
}
}
}
测试类中,可以使用Autowired注入,类名方法名需要一致
//方式一:类名+方法名匹配
@Autowired
private RestHighLevelClient restHighLevelClient;
//或者,自定义变量名称
@Autowired
@Qualifier("restHighLevelClient")
private RestHighLevelClient client;
1.5 使用java操作索引
@SpringBootTest
public class StudyesApiApplicationTests {
//autowried需要指定类型以及相关的方法
/*spring系列的配置类命名一般都是一下格式:
XXXAutoConfigration xxxProperties
*/
@Autowired
@Qualifier("restHighLevelClient")
private RestHighLevelClient client;
//测试索引的创建 需要有REST请求 request请求
@Test
void testCreateIndex() throws IOException {
//创建索引请求
CreateIndexRequest request = new CreateIndexRequest("itxing_index");
//执行创建请求
CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);
System.out.println(createIndexResponse);
}
//测试获取索引,只能够判断索引是否存在
@Test
void testExistIndex()throws IOException{
//指定需要获取的索引
GetIndexRequest getIndex = new GetIndexRequest("itxing_index");
boolean exists = client.indices().exists(getIndex, RequestOptions.DEFAULT);
System.out.println(exists);
}
//测试删除索引
@Test
void testDeleteIndex()throws IOException{
DeleteIndexRequest delete = new DeleteIndexRequest("itxing_index");
AcknowledgedResponse delete1 = client.indices().delete(delete, RequestOptions.DEFAULT);
//得到删除对象,打印删除对象的isAcknowledged的结果,为true表示删除成功
System.out.println(delete1.isAcknowledged());
}
}
1.6 使用java操作文档
创建实体类对象
@Component
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private int age;
}
文档的增、删、改、查以及批量插入操作操作
//添加文档
@Test
void testCreateDoc()throws IOException{
//1.创建对象
User user = new User("itxing",25);
//2.创建请求
IndexRequest request = new IndexRequest("itxing_index");
//3.设置规则 PUT /itxing_index/_doc/1
request.id("1");
request.timeout(TimeValue.timeValueSeconds(1));
request.timeout("1s");
//4.放置请求的数据
request.source(JSON.toJSONString(user), XContentType.JSON);
//5.客户端发送请求
IndexResponse indexResponse = client.index(request, RequestOptions.DEFAULT);
System.out.println(indexResponse.toString());
System.out.println(indexResponse.status());//返回命令的状态,第一次为created
}
//获取文档 GET /index/doc/1
@Test
void testIsExist()throws IOException{
GetRequest getRequest = new GetRequest("itxing_index", "1");
//获取返回的_source的上下文
getRequest.fetchSourceContext(new FetchSourceContext(false));
getRequest.storedFields("_none_");
boolean exists = client.exists(getRequest, RequestOptions.DEFAULT);
System.out.println(exists);
}
//获取文档的信息
@Test
void testDocInfo()throws IOException{
GetRequest getRequest = new GetRequest("itxing_index", "1");
GetResponse response = client.get(getRequest, RequestOptions.DEFAULT);
System.out.println(response.getSourceAsString());//获取的文档内容
System.out.println(response);//返回的全部内容和命令是一样的
}
//更新文档信息,Post /index/_doc/id/_update
@Test
void updateDoc()throws IOException{
UpdateRequest request = new UpdateRequest("itxing_index","1");
request.timeout("1s");
User user = new User("星仔", 23);
request.doc(JSON.toJSONString(user),XContentType.JSON);
UpdateResponse update = client.update(request, RequestOptions.DEFAULT);
System.out.println(update);
System.out.println(update.status());//返回更新的状态 成功返回OK
}
//删除文档
@Test
void deleteDoc()throws IOException{
DeleteRequest request = new DeleteRequest("itxing_index", "1");
request.timeout("1s");
DeleteResponse delete = client.delete(request, RequestOptions.DEFAULT);
System.out.println(delete.status());//返回删除的结果状态 成功返回OK
}
//批量查询、插入
@Test
void testBulkRequest()throws IOException{
BulkRequest bulkRequest = new BulkRequest();
bulkRequest.timeout("10s");
List<User> list = new ArrayList<>();
list.add(new User("张三",21));
list.add(new User("李四",22));
list.add(new User("张三2",25));
list.add(new User("王五",26));
list.add(new User("李二狗",29));
for(int i=0;i<list.size();i++){
//批量插入操作
bulkRequest.add(new IndexRequest(
"itxing_index").id(""+(i+1))
.source(JSON.toJSONString(list.get(i)),XContentType.JSON));
}
BulkResponse bulk = client.bulk(bulkRequest, RequestOptions.DEFAULT);
System.out.println(bulk.hasFailures());//判断结果是否失败,false 代表成功;true代表成功
}
//查询操作
/*
* SearchRequest 搜索请求
* SearchSourceBuilder 条件构造
* HighlightBuilder构建高亮
* TermQueryBuilder精确查询
* MatchAllQueryBuilder 全部匹配查询
* */
@Test
void testSearch()throws IOException{
SearchRequest searchRequest = new SearchRequest("itxing_index");
//构建搜索条件
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//term精确匹配
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", "张三");
//匹配全部查询
// MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
sourceBuilder.query(termQueryBuilder);
sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
//构建分页,起始页,每页展示的条数
// sourceBuilder.from();
// sourceBuilder.size()
searchRequest.source(sourceBuilder);
SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
System.out.println(JSON.toJSONString(search.getHits()));
System.out.println("===========================");
for(SearchHit document:search.getHits().getHits()){
System.out.println(document.getSourceAsMap());
}
}
2. 项目实战
2.1 爬虫
从jd的网站获取自己想要的数据,最后将其创建索引放在自己的ES中,最后可以进行搜索,爬虫使用的是jsoup类。
<!--jsoup解析网页-->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.13.1</version>
</dependency>
爬去的页面主要是搜索的页面jd搜索页面
使用F12可以查看元素中的信息
创建一个Content对象
/**
* @author xing
* @create 2020/7/19-studyes
* 创建一个爬取内容的对象
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Content {
private String title;
private String img;
private String price;
}
将其中的图片的地址信息、价格以及书名爬取下来。
/**
* @author xing
* @create 2020/7/19-studyes
*/
public class HtmlParseUtil {
public static void main(String[] args) throws Exception {
new HtmlParseUtil().parseJD("java").forEach(System.out::println);
}
public List<Content> parseJD(String keyWords)throws Exception{
//连接网络,获取请求 不能获取ajax
String url = "https://search.jd.com/Search?keyword="+keyWords+"&enc=utf-8";
//解析网页
Document document = Jsoup.parse(new URL(url),30000);
//所有js中的方法都能够获取,J_goodsList该参数是京东页面的商品信息的顶级div元素
Element element = document.getElementById("J_goodsList");
//System.out.println(element.html());
//获取所有的li元素
Elements li = element.getElementsByTag("li");
//遍历所有的li标签
//大部分的网站将资源延迟加载
List<Content> list = new ArrayList<>();
for(Element el:li){
//获取商品图片的路径、价格、商品名
String img = el.getElementsByTag("img").eq(0).attr("src");
String price = el.getElementsByClass("p-price").eq(0).text();
String title = el.getElementsByClass("p-name").eq(0).text();
if(img!=""&&price!=""&&title!=""){
Content content = new Content();
content.setImg(img);
content.setPrice(price);
content.setTitle(title);
list.add(content);
}
}
return list;
}
}
2.2 前后端分离
前端使用vue,首先创建vue的项目导入vue的相关js库,创建一个空文件夹,cmd进入命令行,输入以下命令:
npm install vue #前端框架
npm install axios # 这个是前后端通信的
将创建的vue项目中的两个js文件放置在当前的springboot项目下使用,具体的springboot-ES仿jd项目完整版程序放置在gitee上,适用于新手练习使用。
前端的课程依旧推荐狂神说java系列的课程。
2.3高亮显示
高亮显示设置在于使用HighlightBuilder类对参数进行拼接、对高亮的结果进行解析,前端使用vue将前端信息嵌入,项目中的service文件中对不设置高亮以及设置高亮使用了两个方法(searchPage和searchPageHighLight)
后期的学习:Es的集群学习、ES大数据学习、ES的docker环境搭建
小结
从2020年疫情期间遇到狂神,再也没有办法听别的老师的课程了,秦老师讲的是真的好,作为一个技术新人,如何在该行业走的久、走得远是一个值得思考的问题,对于高校的老师们真的很无语,要么就是研究所谓的人生哲学、有的就是金钱、有的就是职称,这个社会我们还是没有发言的权力,自己还是要努力,才能看起来没那么费力,一起努力!!!