<dependency>
<groupId>org.elasticsearchgroupId>
<artifactId>elasticsearchartifactId>
<version>2.4.0version>
dependency>
<dependency>
<groupId>org.springframework.datagroupId>
<artifactId>spring-data-elasticsearchartifactId>
<version>2.0.4.RELEASEversion>
dependency>
@Document : 文档对象(索引信息index,文档类型mapping)
@Id : 文档主键,唯一标识
@Field : 每个文档的域配置
index = FieldIndex.not_analyzed : 不分词
index = FieldIndex.analyzed : 分词
index = FieldIndex.not : 不创建索引
analyzer = “ik” : 指定使用的分词器
store = true : 是否保存
searchAnalyzer = “ik” : 查询所使用的分词器
type = FieldType.String : 指定域的类型
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldIndex;
import org.springframework.data.elasticsearch.annotations.FieldType;
@Document(indexName = "blog3", type = "article")
public class Article {
@Id
@Field(index = FieldIndex.not_analyzed, store = true, type = FieldType.Integer)
private Integer id;
@Field(index = FieldIndex.analyzed, analyzer = "ik", store = true, searchAnalyzer = "ik", type = FieldType.String)
private String title;
@Field(index = FieldIndex.analyzed, analyzer = "ik", store = true, searchAnalyzer = "ik", type = FieldType.String)
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 + "]";
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/data/elasticsearch
http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd ">
<elasticsearch:repositories base-package="cn.itcast.dao" />
<context:component-scan base-package="cn.itcast.service" />
<elasticsearch:transport-client id="client" cluster-nodes="localhost:9300" />
<bean id="elasticsearchTemplate"
class="org.springframework.data.elasticsearch.core.ElasticsearchTemplate">
<constructor-arg name="client" ref="client" />
bean>
beans>
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import cn.itcast.domain.Article;
public interface ArticleRepository extends
ElasticsearchRepository {
List findByTitle(String title);
Page findByTitle(String title, Pageable pageable);
}
错误一 :
java.lang.NoClassDefFoundError:org/springframework/core/ResolvableTypeProvider
错误原因: 导报冲突
解决: spring 导包版本要一致,提升 spring 依赖版本 4.1.7 提升 4.2.8 (最高)
错误二:
MapperParsingException[No type specified for field [title]]
错误三:
Caused by: java.lang.AbstractMethodError: org.springframework.data.jpa.repos
原因:是spring-data-jpa.jar的版本和spring-data-commons-core.jar的版本不匹配所造成的,spring-data-commons-core.jar的版本过高了.
在发生异常的时候我的版本是:spring-data-jpa-1.0.2.RELEASE.jar和spring-data-commons-core-1.3.0.M1.jar
更改后:spring-data-jpa-1.0.2.RELEASE.jar和spring-data-commons-core-1.1.0.RELEASE.jar (OK)
错误原因: 实体类中未指定域的类型
解决: 在是类的字段中添加注解@Field(type = FieldType.String)
问题四:
ElasticSearch使用的是jackson来进行对象序列化的,所以有些时候可能会造成双向关联的对象,在转json的时候,会相互引用,造成栈内存溢出,需要使用@JsonIgnore来排除双向引用的字段
import java.io.IOException;
import java.net.InetAddress;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.Requests;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.highlight.HighlightField;
import org.junit.Test;
import cn.itcast.elasticsearch.domain.Article;
import com.fasterxml.jackson.databind.ObjectMapper;
// ElasticSearch 测试程序
public class ElasticSearchTest {
@Test
// 直接在ElasticSearch中建立文档,自动创建索引
public void demo1() throws IOException {
// 创建连接搜索服务器对象
Client client = TransportClient
.builder()
.build()
.addTransportAddress(
new InetSocketTransportAddress(InetAddress
.getByName("127.0.0.1"), 9300));
// 描述json 数据
/*
* {id:xxx, title:xxx, content:xxx}
*/
XContentBuilder builder = XContentFactory
.jsonBuilder()
.startObject()
.field("id", 1)
.field("title", "ElasticSearch是一个基于Lucene的搜索服务器")
.field("content",
"它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。")
.endObject();
// 建立文档对象
client.prepareIndex("blog1", "article", "1").setSource(builder).get();
// 关闭连接
client.close();
}
@Test
// 搜索在elasticSearch中创建文档对象
public void demo2() throws IOException {
// 创建连接搜索服务器对象
Client client = TransportClient
.builder()
.build()
.addTransportAddress(
new InetSocketTransportAddress(InetAddress
.getByName("127.0.0.1"), 9300));
// 搜索数据
// get() === execute().actionGet()
SearchResponse searchResponse = client.prepareSearch("blog1")
.setTypes("article").setQuery(QueryBuilders.matchAllQuery())
.get();
printSearchResponse(searchResponse);
// 关闭连接
client.close();
}
@Test
// 各种查询使用
public void demo3() throws IOException {
// 创建连接搜索服务器对象
Client client = TransportClient
.builder()
.build()
.addTransportAddress(
new InetSocketTransportAddress(InetAddress
.getByName("127.0.0.1"), 9300));
// 搜索数据
// get() === execute().actionGet()
// SearchResponse searchResponse = client.prepareSearch("blog1")
// .setTypes("article")
// .setQuery(QueryBuilders.queryStringQuery("全面")).get();
// SearchResponse searchResponse = client.prepareSearch("blog1")
// .setTypes("article")
// .setQuery(QueryBuilders.wildcardQuery("content", "*全文*")).get();
SearchResponse searchResponse = client.prepareSearch("blog2")
.setTypes("article")
.setQuery(QueryBuilders.termQuery("content", "搜索")).get();
printSearchResponse(searchResponse);
// 关闭连接
client.close();
}
private void printSearchResponse(SearchResponse searchResponse) {
SearchHits hits = searchResponse.getHits(); // 获取命中次数,查询结果有多少对象
System.out.println("查询结果有:" + hits.getTotalHits() + "条");
Iterator iterator = hits.iterator();
while (iterator.hasNext()) {
SearchHit searchHit = iterator.next(); // 每个查询对象
System.out.println(searchHit.getSourceAsString()); // 获取字符串格式打印
System.out.println("title:" + searchHit.getSource().get("title"));
}
}
@Test
// 索引操作
public void demo4() throws IOException {
// 创建连接搜索服务器对象
Client client = TransportClient
.builder()
.build()
.addTransportAddress(
new InetSocketTransportAddress(InetAddress
.getByName("127.0.0.1"), 9300));
// 创建索引
client.admin().indices().prepareCreate("blog2").get();
// 删除索引
client.admin().indices().prepareDelete("blog2").get();
// 关闭连接
client.close();
}
@Test
// 映射操作
public void demo5() throws IOException, InterruptedException,
ExecutionException {
// 创建连接搜索服务器对象
Client client = TransportClient
.builder()
.build()
.addTransportAddress(
new InetSocketTransportAddress(InetAddress
.getByName("127.0.0.1"), 9300));
// 添加映射
XContentBuilder builder = XContentFactory.jsonBuilder().startObject()
.startObject("article").startObject("properties")
.startObject("id").field("type", "integer")
.field("store", "yes").endObject().startObject("title")
.field("type", "string").field("store", "yes")
.field("analyzer", "ik").endObject().startObject("content")
.field("type", "string").field("store", "yes")
.field("analyzer", "ik").endObject().endObject().endObject()
.endObject();
PutMappingRequest mapping = Requests.putMappingRequest("blog2")
.type("article").source(builder);
client.admin().indices().putMapping(mapping).get();
// 关闭连接
client.close();
}
@Test
// 文档相关操作
public void demo6() throws IOException, InterruptedException,
ExecutionException {
// 创建连接搜索服务器对象
Client client = TransportClient
.builder()
.build()
.addTransportAddress(
new InetSocketTransportAddress(InetAddress
.getByName("127.0.0.1"), 9300));
// 描述json 数据
/*
* {id:xxx, title:xxx, content:xxx}
*/
Article article = new Article();
article.setId(2);
article.setTitle("搜索工作其实很快乐");
article.setContent("我们希望我们的搜索解决方案要快,我们希望有一个零配置和一个完全免费的搜索模式,我们希望能够简单地使用JSON通过HTTP的索引数据,我们希望我们的搜索服务器始终可用,我们希望能够一台开始并扩展到数百,我们要实时搜索,我们要简单的多租户,我们希望建立一个云的解决方案。Elasticsearch旨在解决所有这些问题和更多的问题。");
ObjectMapper objectMapper = new ObjectMapper();
// 建立文档
// client.prepareIndex("blog2", "article", article.getId().toString())
// .setSource(objectMapper.writeValueAsString(article)).get();
// 修改文档
// client.prepareUpdate("blog2", "article", article.getId().toString())
// .setDoc(objectMapper.writeValueAsString(article)).get();
// 修改文档
// client.update(
// new UpdateRequest("blog2", "article", article.getId()
// .toString()).doc(objectMapper
// .writeValueAsString(article))).get();
// 删除文档
// client.prepareDelete("blog2", "article", article.getId().toString())
// .get();
// 删除文档
client.delete(
new DeleteRequest("blog2", "article", article.getId()
.toString())).get();
// 关闭连接
client.close();
}
@Test
// 批量查询100条记录
public void demo7() throws IOException, InterruptedException,
ExecutionException {
// 创建连接搜索服务器对象
Client client = TransportClient
.builder()
.build()
.addTransportAddress(
new InetSocketTransportAddress(InetAddress
.getByName("127.0.0.1"), 9300));
ObjectMapper objectMapper = new ObjectMapper();
for (int i = 1; i <= 100; i++) {
// 描述json 数据
Article article = new Article();
article.setId(i);
article.setTitle(i + "搜索工作其实很快乐");
article.setContent(i
+ "我们希望我们的搜索解决方案要快,我们希望有一个零配置和一个完全免费的搜索模式,我们希望能够简单地使用JSON通过HTTP的索引数据,我们希望我们的搜索服务器始终可用,我们希望能够一台开始并扩展到数百,我们要实时搜索,我们要简单的多租户,我们希望建立一个云的解决方案。Elasticsearch旨在解决所有这些问题和更多的问题。");
// 建立文档
client.prepareIndex("blog2", "article", article.getId().toString())
.setSource(objectMapper.writeValueAsString(article)).get();
}
// 关闭连接
client.close();
}
@Test
// 分页搜索
public void demo8() throws IOException {
// 创建连接搜索服务器对象
Client client = TransportClient
.builder()
.build()
.addTransportAddress(
new InetSocketTransportAddress(InetAddress
.getByName("127.0.0.1"), 9300));
// 搜索数据
// get() === execute().actionGet()
SearchRequestBuilder searchRequestBuilder = client
.prepareSearch("blog2").setTypes("article")
.setQuery(QueryBuilders.matchAllQuery());
// 查询第2页数据,每页20条
searchRequestBuilder.setFrom(20).setSize(20);
SearchResponse searchResponse = searchRequestBuilder.get();
printSearchResponse(searchResponse);
// 关闭连接
client.close();
}
@Test
// 高亮查询结果 处理 搜索
public void demo9() throws IOException {
// 创建连接搜索服务器对象
Client client = TransportClient
.builder()
.build()
.addTransportAddress(
new InetSocketTransportAddress(InetAddress
.getByName("127.0.0.1"), 9300));
ObjectMapper objectMapper = new ObjectMapper();
// 搜索数据
SearchRequestBuilder searchRequestBuilder = client
.prepareSearch("blog2").setTypes("article")
.setQuery(QueryBuilders.termQuery("title", "搜索"));
// 高亮定义
searchRequestBuilder.addHighlightedField("title"); // 对title字段进行高亮
searchRequestBuilder.setHighlighterPreTags(""); // 前置元素
searchRequestBuilder.setHighlighterPostTags("");// 后置元素
SearchResponse searchResponse = searchRequestBuilder.get();
SearchHits hits = searchResponse.getHits(); // 获取命中次数,查询结果有多少对象
System.out.println("查询结果有:" + hits.getTotalHits() + "条");
Iterator iterator = hits.iterator();
while (iterator.hasNext()) {
SearchHit searchHit = iterator.next(); // 每个查询对象
// 将高亮处理后内容,替换原有内容 (原有内容,可能会出现显示不全 )
Map highlightFields = searchHit
.getHighlightFields();
HighlightField titleField = highlightFields.get("title");
// 获取到原有内容中 每个高亮显示 集中位置 fragment 就是高亮片段
Text[] fragments = titleField.fragments();
String title = "";
for (Text text : fragments) {
title += text;
}
// 将查询结果转换为对象
Article article = objectMapper.readValue(
searchHit.getSourceAsString(), Article.class);
// 用高亮后内容,替换原有内容
article.setTitle(title);
System.out.println(article);
}
// 关闭连接
client.close();
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
xsi:schemaLocation="http://www.springframework.org/schema/data/elasticsearch http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<elasticsearch:repositories base-package="cn.itcast.bos.index" />
<elasticsearch:transport-client id="client"
cluster-nodes="localhost:9300" />
<bean id="elasticsearchTemplate"
class="org.springframework.data.elasticsearch.core.ElasticsearchTemplate">
<constructor-arg name="client" ref="client" />
bean>
beans>
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import cn.itcast.bos.domain.delivery.WayBill;
public interface WayBillIndexRepository extends ElasticsearchRepository<WayBill, Integer> {
}
// 执行保存索引库
wayBillIndexRepository.save(entity);
/**
* 分页查询索引库
*/
@Override
public void findPage(WayBill wayBill, PageBean pageBean) {
BoolQueryBuilder query = new BoolQueryBuilder();
if (StringUtils.isNotBlank(wayBill.getWayBillNum())) {
// 设置运单号条件
QueryBuilder termQuery = new TermQueryBuilder("wayBillNum", wayBill.getWayBillNum());
query.must(termQuery);
}
if (StringUtils.isNotBlank(wayBill.getSendAddress())) {
// 设置发送地址条件
BoolQueryBuilder boolQuery = new BoolQueryBuilder();
QueryBuilder wildcardQuery = new WildcardQueryBuilder("sendAddress", "*" + wayBill.getSendAddress() + "*");
QueryBuilder queryStringQuery = new QueryStringQueryBuilder(wayBill.getSendAddress()).field("sendAddress")
.defaultOperator(Operator.AND);
boolQuery.should(wildcardQuery);
boolQuery.should(queryStringQuery);
query.must(boolQuery);
}
if (StringUtils.isNotBlank(wayBill.getRecAddress())) {
// 设置接收地址条件
BoolQueryBuilder boolQuery = new BoolQueryBuilder();
QueryBuilder wildcardQuery = new WildcardQueryBuilder("recAddress", "*" + wayBill.getRecAddress() + "*");
QueryBuilder queryStringQuery = new QueryStringQueryBuilder(wayBill.getRecAddress()).field("recAddress")
.defaultOperator(Operator.AND);
boolQuery.should(wildcardQuery);
boolQuery.should(queryStringQuery);
query.must(boolQuery);
}
if (StringUtils.isNotBlank(wayBill.getSendProNum())) {
// 设置产品类型条件
QueryBuilder termQuery = new TermQueryBuilder("sendProNum", wayBill.getSendProNum());
query.must(termQuery);
}
if (wayBill.getSignStatus() != null && wayBill.getSignStatus() != 0) {
// 设置快递产品类型编号条件
QueryBuilder termQuery = new TermQueryBuilder("signStatus", wayBill.getSignStatus());
query.must(termQuery);
}
Page search = wayBillIndexRepository.search(query,
new PageRequest(pageBean.getCurrentPage() - 1, pageBean.getPageSize()));
pageBean.setRows(search.getContent());
pageBean.setTotal(search.getTotalElements());
}