Spring和Elasticsearch的整合

POM.XML

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.bawei</groupId>
  <artifactId>1709d_es</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  <dependencies>
  			<!-- elasticsearch和spring的整合包 -->
		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-elasticsearch</artifactId>
			<version>3.1.2.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>5.1.2.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.17</version>
		</dependency>
  </dependencies>
  
  <!-- 编译 -->
  <build>
  	<plugins>
  		<plugin>
  			<groupId>org.apache.maven.plugins</groupId>
  			<artifactId>maven-compiler-plugin</artifactId>
  			<version>3.8.0</version>
  			<configuration>
  				<source>1.8</source>
  				<target>1.8</target>
  			</configuration>
  		</plugin>
  	</plugins>
  </build>
</project>

创建spring-elasticsearch.xml的配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/data/elasticsearch http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch.xsd
                            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
    <!-- 扫描Dao包,自动创建实例 -->
	<elasticsearch:repositories base-package="com.haoge.dao" />
	<!-- 扫描Service包,创建Service的实体 -->
	<!-- <context:component-scan base-package="com.haoge.service" /> --> <!-- 配置elasticSearch的连接 -->
	<!-- es提供了2个端口号:92009300
		9200:对浏览器暴露的端口号
		9300:是对java编程需要操作es所暴露的端口号
	 -->
	<elasticsearch:transport-client id="client"
		cluster-nodes="192.168.237.129:9300" /> <!-- spring data elasticSearcheDao 必须继承 ElasticsearchTemplate -->
		
	<bean id="elasticsearchTemplate"
		class="org.springframework.data.elasticsearch.core.ElasticsearchTemplate">
		<constructor-arg name="client" ref="client"></constructor-arg>
	</bean>
    
</beans>

修改配置文件中的相关信息

  1. 扫描包的路径
  2. ip地址

进行数据的增删改查操作

第一种方法

1. 创建ArticleRepository 接口 让其继承ElasticsearchRepository接口,进行简单的CRUD操作

//让ArticleRepository继承ElasticsearchRepository,此时这个借口就自动具备了简单的CRUD操作的功能
//  Article操作的实体类类型 ,Integer实体类主键类型
public interface ArticleRepository extends ElasticsearchRepository<Article,Integer >{

	//定义根据标题查询的抽象方法
	//疑问?为什么在这里定义一个抽象方法,就可以直接调用使用了呢?
	//这个方法名称不是乱写的,如果要查询,必须findByTitle,findByTitleAndContent,findByTitleOrContent
	List<Article> findByTitle(String title);
	
	//根据标题或内容查询
	List<Article> findByTitleOrContent(String title,String content);
}

该类定义的查询方法名必须遵守规则(findBy*****)
在这里插入图片描述

2. 创建实体类Article

//索引名称和类型名称一律小写(如果是大写,就会报错)
//indexName相当于数据库,type相当于数据表
@Document(indexName="article",type="article")
public class Article implements Serializable{
	@Id
	private Integer id;
	// Field的相关参数的意义   1.是否对此字段建立索引,2.是否对此字段的值进行存储,3.对此字段的值分词方式是ik_smart,4.搜索关键字是否分词5.指定字段值的类型
	@Field(index=true,store=true,analyzer="ik_smart",searchAnalyzer="ik_smart",type=FieldType.text)
	private String title;
	//  1.是否对此字段建立索引,2.是否对此字段的值进行存储,3.对此字段的值分词方式是ik_smart,4.搜索关键字是否分词5.指定字段值的类型
	@Field(index=true,store=true,analyzer="ik_smart",searchAnalyzer="ik_smart",type=FieldType.text)
	private String content;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	@Override
	public String toString() {
		return "Article [id=" + id + ", title=" + title + ", content=" + content + "]";
	}	
}

3. 开启elasticsearch和elasticsearch的头文件
启动elasticsearch的操作一定要在非root的用户
切换用户 su es cd elasticsearch-6.6.2目录下
开启:bin/elasticseeeearch (-d)后台启动
开启头文件 cd/elasticsearch-head-master
cnpm run start
192.168.237.129:9200(9100)9300
4. 创建测试类,进行数据增删改查的测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-elasticsearch.xml")
public class EsTest {

	@Autowired
	 ArticleRepository articleRepository;	
	@Test
	//测试添加
	public void add() {		
		Article article = new Article();
		article.setId(3);
		article.setTitle("森林狼啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊26记三分的最新相关信息");
		article.setContent("打疯啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊了!142-115大胜快船!森林狼26记三分  上海热线\r\n" + 
				"并且全队狂轰26记三分球打破了球队历史记录! 在比赛之前,快船36胜16负,排在西部第三,森林狼16胜35负,排在西部倒数第二,可以说两队的实力相差悬殊,快...");
		
		Article save = articleRepository.save(article);		
		System.out.println("添加成功");		
	}
	@Test
	//测试修改
	public void update() {		
		Article article = new Article();
		article.setId(3);
		article.setTitle("奥斯卡颁奖的最新相关信息");
		article.setContent("2小时前 乌拉乌拉卡夫卡 很卡获得了奥斯卡.");
		Article save = articleRepository.save(article);
		System.out.println("修改成功");
	}
	//测试删除
	@Test
	public void delete() {		
		articleRepository.deleteById(2);
		System.out.println("删除成功");
	}
	@Test
	//测试查询
	public void select() {		
	   List<Article> articleList = articleRepository.findByTitleAndContent("三分","打疯了");
	   for (Article article : articleList) {
		System.out.println(article);
	}
	}

5.结果
在这里插入图片描述

第二种方法

1.创建实体类Student

@Document(type = "student",indexName = "cms")
public class Student {

	@Id
	private Integer id;
	@Field(fielddata = true)
	private String name;
	private Date birthday;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Date getBirthday() {
		return birthday;
	}
	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}
	public Student() {
		super();
		// TODO Auto-generated constructor stub
	}
	public Student(Integer id, String name, Date birthday) {
		super();
		this.id = id;
		this.name = name;
		this.birthday = birthday;
	}
	@Override
	public String toString() {
		return "Student [id=" + id + ", name=" + name + ", birthday=" + birthday + "]";
	}	
}

2.创建测试类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-elasticsearch.xml")
public class EsTest {

	@Resource
	private ElasticsearchTemplate elasticsearchTemplate;
	
	//创建索引
	@Test
	public void testIndex() {
		//创建
		elasticsearchTemplate.createIndex("cms");
		//删除
		elasticsearchTemplate.deleteIndex("cms");
		System.out.println("创建完毕");
		
	}
	//插入数据
	@Test
	public void addTest() {
		//批量添加
		for (int i = 4; i <=100; i++) {
			Student student = new Student(i,"宋江"+i,new Date());
			IndexQuery query = new IndexQueryBuilder().withId(student.getId().toString()).withObject(student).build();
			elasticsearchTemplate.index(query);
			System.out.println("插入完毕");
		}
		
	      
		//第一种方式
		  IndexQuery query = new IndexQuery(); 
		  query.setId(student.getId()+""); query.setObject(student);
		 
	    //第二中方式
		IndexQuery query = new IndexQueryBuilder().withId(student.getId().toString()).withObject(student).build();
		
		elasticsearchTemplate.index(query);
	    System.out.println("插入完毕");
	}
	
    //修改数据
	@Test
	public void updTest() {
		Student student = new Student(1,"及时雨",new Date());
		//第一种方式
		  IndexQuery query = new IndexQuery();
		  query.setId(student.getId()+""); query.setObject(student);
	    //第二种方式
		IndexQuery query = new IndexQueryBuilder().withId(student.getId().toString()).withObject(student).build();
		elasticsearchTemplate.index(query);
	     System.out.println("修改完毕");
	}
	//删除数据
	@Test
	public void delTest() {
		elasticsearchTemplate.delete(Student.class, 2+"");
		System.out.println("删除完毕");
	}
	//查询数据
	@Test
	public void findOneTest() {
		//创建查询条件
        GetQuery query = new GetQuery();
		query.setId("3");
        Student student = elasticsearchTemplate.queryForObject(query , Student.class);
        System.out.println(student.toString());    
	}
	//查询所有数据
	@Test
	public void findAllTest() {
		//构造器 默认一次查询10条记录
		SearchQuery query = new NativeSearchQueryBuilder().build();
		List<Student> queryForList = elasticsearchTemplate.queryForList(query , Student.class);
		for (Student student : queryForList) {
			System.out.println(student);
		}	  
	}
	//模糊查询
	@Test
	public void findMHTest() {
		//封装模糊查询条件
		QueryBuilder queryBuilder = QueryBuilders.multiMatchQuery("及", "name");
		//构造器 默认一次查询10条记录
		SearchQuery query = new NativeSearchQueryBuilder().withQuery(queryBuilder).build();
		List<Student> queryForList = elasticsearchTemplate.queryForList(query , Student.class);
		  for (Student student : queryForList) {
			System.out.println(student);
		}	  
	}
	//分页查询
	@Test
	public void pageTest() {
		//封装分页查询条件,      当前页,每页条数,排序方式,排序字段
		 Pageable pageable = PageRequest.of(1, 20, Sort.by(Direction.ASC, "name"));
		//封装查询对象
		SearchQuery build = new NativeSearchQueryBuilder().withPageable(pageable).build();	
		List<Student> queryForList = elasticsearchTemplate.queryForList(build, Student.class);	
		for (Student student : queryForList) {
			System.out.println(student);
		}
	}
	//迷糊+分页查询
	@Test
	public void pageAndMHTest() {	
		//封装分页查询条件,      当前页,每页条数,排序方式,排序字段
		 Pageable pageable = PageRequest.of(1, 20, Sort.by(Direction.ASC, "id"));
		QueryBuilder queryBuilder =QueryBuilders.multiMatchQuery("宋", "name");
		//封装查询对象
		SearchQuery build = new NativeSearchQueryBuilder().withQuery(queryBuilder ).withPageable(pageable).build();
	
		List<Student> queryForList = elasticsearchTemplate.queryForList(build, Student.class);
		
		for (Student student : queryForList) {
			System.out.println(student);
		}
	}
	//高亮查询
	@Test
	public void highLightTest() {		
		//                     模板对象               实体类的class对象      实体类中成员变量是其他实体类对象,list类型
		//ESUtils.selectObjects(elasticsearchTemplate ,clazz,           classes, 
		 // 当前页从0开始     每页条数           排序字段                要查询的字段, String数组        要查询的数据
		//page,           pageSize, sortField, fieldNames,         value)
		AggregatedPage<Student> selectObjects = ESUtils.selectObjects(elasticsearchTemplate, Student.class, null, 0, 20, "id", new String[] {"name"}, "宋");
		
		List<Student> list = selectObjects.getContent();
		
		for (Student student : list) {
			System.out.println(student);
		}
	}
	
}

注:高亮查询的工具类(该工具类非本人所写)

public class ESUtils {

	private static Logger logger = Logger.getLogger(ESUtils.class);

	/**
	 * 保存及更新方法
	 * 
	 * @param elasticsearchTemplate
	 * @param id
	 * @param object
	 */
	public static void saveObject(ElasticsearchTemplate elasticsearchTemplate, String id, Object object) {
		// 创建所以对象
		IndexQuery query = new IndexQueryBuilder().withId(id).withObject(object).build();
		// 建立索引
		elasticsearchTemplate.index(query);
	}

	/**
	 * 批量删除
	 * 
	 * @param elasticsearchTemplate
	 * @param clazz
	 * @param ids
	 */
	public static void deleteObject(ElasticsearchTemplate elasticsearchTemplate, Class<?> clazz, Integer ids[]) {
		for (Integer id : ids) {
			// 建立索引
			elasticsearchTemplate.delete(clazz, id + "");
		}
	}

	/**
	 * 
	 * @Title: selectById
	 * @Description: 根据id在es服务启中查询对象
	 * @param elasticsearchTemplate
	 * @param clazz
	 * @param id
	 * @return
	 * @return: Object
	 */
	public static Object selectById(ElasticsearchTemplate elasticsearchTemplate, Class<?> clazz, Integer id) {
		GetQuery query = new GetQuery();
		query.setId(id + "");
		return elasticsearchTemplate.queryForObject(query, clazz);
	}
	// 查询操作
	/**
	 * 
	 * @param elasticsearchTemplate 模板对象
	 * @param clazz	实体类的class对象
	 * @param classes 实体类中实体类型的成员变量的类的class集合
	 * @param page	当前页,从0开始
	 * @param pageSize	每页的条数
	 * @param sortField	根据这个字段进行排序
	 * @param fieldNames	要搜索的字段名
	 * @param value	具体要搜索的数据
	 * @return
	 */
	public static <T> AggregatedPage<T> selectObjects(ElasticsearchTemplate elasticsearchTemplate, Class<T> clazz,
			List<Class> classes,Integer page, Integer pageSize, String sortField, String fieldNames[], String value) {
		AggregatedPage<T> pageInfo = null;
		logger.info("采用es进行数据库的查询操作开始!!!!!!!!!!!!!!!!!!!!!!!!");
		// 创建Pageable对象
		final Pageable pageable = PageRequest.of(page, pageSize, Sort.by(Sort.Direction.ASC, sortField));
		//查询对象
		SearchQuery query = null;
		//查询条件高亮的构建对象
		QueryBuilder queryBuilder = null;
		
		if (value != null && !"".equals(value)) {
			// 高亮拼接的前缀与后缀
			String preTags = "<font color=\"red\">";
			String postTags = "</font>";

			// 定义创建高亮的构建集合对象
			HighlightBuilder.Field highlightFields[] = new HighlightBuilder.Field[fieldNames.length];

			for (int i = 0; i < fieldNames.length; i++) {
				// 这个代码有问题
				highlightFields[i] = new HighlightBuilder.Field(fieldNames[i]).preTags(preTags).postTags(postTags);
			}

			// 创建queryBuilder对象
			queryBuilder = QueryBuilders.multiMatchQuery(value, fieldNames);
			query = new NativeSearchQueryBuilder().withQuery(queryBuilder).withHighlightFields(highlightFields)
					.withPageable(pageable).build();

			pageInfo = elasticsearchTemplate.queryForPage(query, clazz, new SearchResultMapper() {

				@Override
				public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable1) {
					
					List<T> content = new ArrayList<T>();
					long total = 0l;

					try {
						// 查询结果
						SearchHits hits = response.getHits();
						if (hits != null) {
							//获取总记录数
							total = hits.getTotalHits();
							// 获取结果数组
							SearchHit[] searchHits = hits.getHits();
							// 判断结果
							if (searchHits != null && searchHits.length > 0) {
								// 遍历结果
								for (int i = 0; i < searchHits.length; i++) {
									// 对象值
									T entity = clazz.newInstance();

									// 获取具体的结果
									SearchHit searchHit = searchHits[i]; 

									// 获取对象的所有的字段
									Field[] fields = clazz.getDeclaredFields();

									// 遍历字段对象
									for (int k = 0; k < fields.length; k++) {
										// 获取字段对象
										Field field = fields[k];
										// 暴力反射
										field.setAccessible(true);
										// 字段名称
										String fieldName = field.getName();
										if (!fieldName.equals("serialVersionUID")) {
											HighlightField highlightField = searchHit.getHighlightFields()
													.get(fieldName);
											if (highlightField != null) {
												// 高亮 处理 拿到 被<font color='red'> </font>结束所包围的内容部分
												String value = highlightField.getFragments()[0].toString();
												// 注意一下他是否是 string类型
												field.set(entity, value);
											} else {
												//获取某个字段对应的 value值
												Object value = searchHit.getSourceAsMap().get(fieldName);
//												System.out.println(value);
												// 获取字段的类型
												Class<?> type = field.getType();
												if (type == Date.class) {
													if (value != null) {
														
														//如果不为空,则转换成Date类型
														
														Date value_date = null;
														if(value.getClass() == Long.class) {
															//如果是Long类型
															value_date = new Date(Long.valueOf(value + ""));
															
														}else {
															//如果是String类型
															SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
															
															value_date = sdf.parse(value.toString());
														}
														
														// bug
														field.set(entity, value_date);
														
													}
												} else if (type.isEnum()){
													if(value != null) {
														//枚举
														field.set(entity, Enum.valueOf((Class<Enum>) type, value.toString()));
													}
													
												} else if (classes != null && classes.contains(type)){
													if(value != null) {
														
														//将实体类对象实例化
														Object obj = getEntityObject(value, type ,classes);
												    
														//将对象赋值
														field.set(entity, obj);
													}
												} else{
													field.set(entity, value);
												}
											}
										}
									}

									content.add(entity);
								}
							}
						}
					} catch (Exception e) {
						e.printStackTrace();
					}
					
					
					return new AggregatedPageImpl<T>(content, pageable, total);
				}
				
				//递归方法,生成实体类对象
				private Object getEntityObject(Object value, Class<?> type, List<Class> classes)
						throws InstantiationException, IllegalAccessException, ParseException {
					//实体类
					Object obj = type.newInstance();
					Map map = (HashMap)value;
					
					//获取所有字段
					Field[] fields2 = type.getDeclaredFields();
					for (Field field2 : fields2) {
						
						//排除静态变量和常量
					    int mod = field2.getModifiers();
					    if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
					        continue;
					    }
 
					    //暴力反射
					    field2.setAccessible(true);
					    
					    //从map中获取对应的字段的值
					    Object value2 = map.get(field2.getName());
					    
					    //处理日期Date类型
					    Class<?> type2 = field2.getType();
					    if (type2 == Date.class) {
							if (value2 != null) {
								//如果不为空,则转换成Date类型
								
								Date value2_date = null;
								if(value2.getClass() == Long.class) {
									//如果是Long类型
									value2_date = new Date(Long.valueOf(value2 + ""));
									
								}else {
									//如果是String类型
									SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
									
									value2_date = sdf.parse(value2.toString());
								}
								
								// bug
								field2.set(obj, value2_date);
							}
						}else if (type2.isEnum()){
							if(value2 != null) {
								//枚举
								field2.set(obj, Enum.valueOf((Class<Enum>) type2, value2.toString()));
							}
						} else if (classes != null && classes.contains(type2)){
							if(value2 != null) {
								
								//将实体类对象实例化
								Object obj2 = getEntityObject(value2, type2 ,classes);
						    
								//将对象赋值
								field2.set(obj, obj2);
							}
						} else {
							
							field2.set(obj, value2);
						}
					    
					}
					return obj;
				}
			});

		} else {
			// 没有查询条件的的时候,获取es中的全部数据 分页获取
			query = new NativeSearchQueryBuilder().withPageable(pageable).build();
			pageInfo = elasticsearchTemplate.queryForPage(query, clazz);
		}
		return pageInfo;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值