spring data elasticsearch在使用5.x版本遇到的坑

一、spring data elasticsearch整合了elasticsearch本来可以很方便的使用,但是当你在spring data jpa框架中使用就会出现spring-data-commons版本冲突问题,那么这个时候就不能直接使用spring data elasticsearch来操作elasticsearch5.x了,这个时候可以使用客户端来操作elasticsearch5.x,pom如下:

               
			org.elasticsearch.client
			transport
			5.6.3
		

二、elasticsearch5.x默认的分词器简直不堪入目,所以我们需要使用HanLP分词器(下载地址:https://github.com/pengcong90/elasticsearch-analysis-hanlp/releases)

安装步骤:

1、下载插件并解压到es的plugins目录下

修改analysis-hanlp目录下的hanlp.properties文件,修改root的属性,值为analysis-hanlp下的data 目录的地址

修改analysis-hanlp目录下的plugin-descriptor.properties文件,
修改elasticsearch的版本为你当前的版本elasticsearch.version=你的es版本号(like:5.5.1)

2、修改es config目录下的jvm.options文件,最后一行添加

-Djava.security.policy=../plugins/analysis-hanlp/plugin-security.policy

重启es

GET /_analyze?analyzer=hanlp-index&pretty=true 

{ 

"text":"张柏芝士蛋糕店" 

}

三、是不是像步骤二一样安装了,查询就直接默认的是hanlp-index(HanLP分词器)分词器?

       答案是错的。我们需要在创建索引的时候,指定每个字段的值按照什么样的分词器来查询,如下:

第一步:创建索引
        @Override
	public boolean createIndex(String indexName) {
		boolean flag = false;
		try {
			CreateIndexResponse indexResponse = client.admin().indices().prepareCreate(indexName).get();
			flag = indexResponse.isAcknowledged();
		} catch (ElasticsearchException e) {
			flag = false;
			logger.warn("create index fialed", e);
		}
		return flag;
	}

	/** * 给索引增加mapping。 * @param index 索引名 * @param type mapping所对应的type */
	
第二步:创建mapper
@Override
	public boolean addMapping(String index, String type, M obj) {
		boolean flag = false;
		try {
			List propertes = getPropertyVOInfo(obj);
			// 使用XContentBuilder创建Mapping
			XContentBuilder builder = XContentFactory.jsonBuilder().startObject().startObject("properties");
			for (PropertyVO propertyVO : propertes) {
				builder.startObject(propertyVO.getFieldName()).field("type", propertyVO.getType());
				if (StringUtils.isNotBlank(propertyVO.getAnalyzer())) {
					builder.field("analyzer", propertyVO.getAnalyzer()).endObject();
				} else if (TypeProp.DATE.equals(propertyVO.getType())) {
					builder.field("format", "strict_date_optional_time||epoch_millis").endObject();
				} else {
					builder.endObject();
				}
			}
			builder.endObject().endObject();
			PutMappingRequest mappingRequest = Requests.putMappingRequest(index).source(builder).type(type);
			PutMappingResponse mappingResponse = client.admin().indices().putMapping(mappingRequest).actionGet();
			flag = mappingResponse.isAcknowledged();
		} catch (ElasticsearchException e) {
			logger.warn("create mapping fialed", e);
			flag = false;
		} catch (IOException e) {
			logger.warn("create mapping fialed", e);
			flag = false;
		}
		return flag;
	}

第三步:创建doc

	@Override
	public void createDoc(TransportClient client, String index, String type, List items) {

		try {
			for (M obj : items) {
				// 使用XContentBuilder创建一个doc source
				XContentBuilder builder = XContentFactory.jsonBuilder().startObject();
				Field[] fields = obj.getClass().getDeclaredFields();
				String id = "" + ReflectionUtils.getFieldValue(obj, "id");
				for (Field field : fields) {
					if (field.getName().equals("serialVersionUID")) {
						continue;
					}
					String name = field.getName();
					String fieldType = field.getGenericType().toString();
					String newName = field.getName().replaceFirst(name.substring(0, 1),
							name.substring(0, 1).toUpperCase());
					Method m;
					try {
						// 如果type是类类型,则前面包含"class ",后面跟类名
						m = obj.getClass().getMethod("get" + newName);
						// 调用getter方法获取属性值
						Object value = m.invoke(obj);
						// 日期类型需要这样处理,不然保存会报错,至于为什么,目前不清楚,但是这样做就是对的
						if (fieldType.equals("class java.util.Date")) {
							Date date = (Date) value;
							builder.field(name, date);
						} else {
							builder.field(name, value);
						}
					} catch (IllegalAccessException e) {
						logger.warn("IllegalAccessException..." + e);
					} catch (IllegalArgumentException e) {
						logger.warn("IllegalArgumentException..." + e);
					} catch (InvocationTargetException e) {
						logger.warn("InvocationTargetException..." + e);
					} catch (NoSuchMethodException e) {
						logger.warn("NoSuchMethodException..." + e);
					} catch (SecurityException e) {
						logger.warn("SecurityException..." + e);
					}
				}
				builder.endObject();
				client.prepareIndex().setIndex(index).setType(type).setId(id).setSource(builder).get();
			}
		} catch (ElasticsearchException e) {
			logger.warn("create doc fialed", e);
		} catch (IOException e) {
			logger.warn("create doc fialed", e);
		}
	}

	private List getPropertyVOInfo(M obj) {
		List result = Lists.newArrayList();
		Field[] fields = obj.getClass().getDeclaredFields();
		// 循环实体类字段集合,获取标注@ColumnConfig的字段
		for (Field field : fields) {
			if (field.getName().equals("serialVersionUID")) {
				continue;
			}
			PropertyVO vo = new PropertyVO();
			String fieldName = field.getName();
			String fieldType = field.getGenericType().toString();
			if (fieldType.equals("class java.lang.String")) {
				fieldType = "string";
			}
			if (fieldType.equals("class java.util.Date")) {
				fieldType = "date";
			}
			try {
				ElasticAnnotation anno = null;
				if (field.isAnnotationPresent(ElasticAnnotation.class)) {
					anno = field.getAnnotation(ElasticAnnotation.class);
				}
				String analyzer = anno == null ? "" : anno.analyzer();
				vo.setFieldName(fieldName);
				vo.setType(fieldType);
				vo.setAnalyzer(analyzer);
				result.add(vo);
			} catch (IllegalArgumentException e) {
				logger.warn(e);
			}
		}
		return result;
	}

你可能感兴趣的:(spring data elasticsearch在使用5.x版本遇到的坑)