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;
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章