public class CustomElasticsearchRepositoryFactory extends RepositoryFactorySupport {
private final ElasticsearchOperations elasticsearchOperations;
private final ElasticsearchEntityInformationCreator entityInformationCreator;
private String indexName;
private String indexType;
public CustomElasticsearchRepositoryFactory(ElasticsearchOperations elasticsearchOperations, String indexName,String indexType) {
Assert.notNull(elasticsearchOperations, "ElasticsearchOperations must not be null!");
this.elasticsearchOperations = elasticsearchOperations;
this.indexName = indexName;
this.indexType = indexType;
this.entityInformationCreator = new ElasticsearchEntityInformationCreatorImpl(elasticsearchOperations.getElasticsearchConverter().getMappingContext());
}
private void setEntityInformationIndexName(MappingElasticsearchEntityInformation entityInformation) {
try {
Field field = MappingElasticsearchEntityInformation.class.getDeclaredField("indexName");
field.setAccessible(true);
String indexDefault = field.get(entityInformation).toString();
if (!StringUtils.isEmpty(this.indexName)) {
field.set(entityInformation, this.indexName);
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
public <T, ID> ElasticsearchEntityInformation<T, ID> getEntityInformation(Class<T> domainClass) {
ElasticsearchEntityInformation entityInformation = this.entityInformationCreator.getEntityInformation(domainClass);
if (!StringUtils.isEmpty(this.indexName)) {
setEntityInformationIndexName((MappingElasticsearchEntityInformation) entityInformation);
}
return entityInformation;
}
protected Object getTargetRepository(RepositoryInformation metadata) {
return this.getTargetRepositoryViaReflection(metadata, new Object[]{this.getEntityInformation(metadata.getDomainType()), this.elasticsearchOperations});
}
@Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
if (isQueryDslRepository(metadata.getRepositoryInterface())) {
throw new IllegalArgumentException("QueryDsl Support has not been implemented yet.");
}
return SimpleElasticsearchRepository.class;
}
private static boolean isQueryDslRepository(Class<?> repositoryInterface) {
return QuerydslUtils.QUERY_DSL_PRESENT && QuerydslPredicateExecutor.class.isAssignableFrom(repositoryInterface);
}
private class ElasticsearchQueryLookupStrategy implements QueryLookupStrategy {
private ElasticsearchQueryLookupStrategy() {
}
public RepositoryQuery resolveQuery(java.lang.reflect.Method method, RepositoryMetadata metadata, ProjectionFactory factory, NamedQueries namedQueries) {
ElasticsearchQueryMethod queryMethod = new ElasticsearchQueryMethod(method, metadata, factory,
elasticsearchOperations.getElasticsearchConverter().getMappingContext());
String namedQueryName = queryMethod.getNamedQueryName();
if (namedQueries.hasQuery(namedQueryName)) {
String namedQuery = namedQueries.getQuery(namedQueryName);
return new ElasticsearchStringQuery(queryMethod, CustomElasticsearchRepositoryFactory.this.elasticsearchOperations, namedQuery);
} else {
return (RepositoryQuery) (queryMethod.hasAnnotatedQuery() ? new ElasticsearchStringQuery(queryMethod, CustomElasticsearchRepositoryFactory.this.elasticsearchOperations, queryMethod.getAnnotatedQuery()) : new ElasticsearchPartQuery(queryMethod, CustomElasticsearchRepositoryFactory.this.elasticsearchOperations));
}
}
}
protected Optional<QueryLookupStrategy> getQueryLookupStrategy(QueryLookupStrategy.Key key, EvaluationContextProvider evaluationContextProvider) {
return Optional.of(new CustomElasticsearchRepositoryFactory.ElasticsearchQueryLookupStrategy());
}
}
@Component
@Scope("prototype")
public class DynamicIndexElasticsearchTemplate implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Autowired
private ESTransportClient eSTransportClient;
protected ElasticsearchTemplate getElasticsearchTemplate() {
return new ElasticsearchTemplate(eSTransportClient.client());
}
public ElasticsearchTemplate getElasticsearchTemplate(String indexName,String indexType, Class cls) {
ElasticsearchTemplate esTemplate = getElasticsearchTemplate();
setIndex(indexName, cls, esTemplate);
setType(indexType, cls, esTemplate);
return esTemplate;
}
protected void setIndex(String indexName, Class cls, ElasticsearchTemplate elasticsearchTemplate) {
ElasticsearchPersistentEntity entity = elasticsearchTemplate.getPersistentEntityFor(cls);
try {
Field field = SimpleElasticsearchPersistentEntity.class.getDeclaredField("indexName");
field.setAccessible(true);
String indexDefault = field.get(entity).toString();
if (!StringUtils.isEmpty(indexName)) {
field.set(entity, indexName);
}
String indexDefault2 = field.get(entity).toString();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
protected void setType(String type, Class cls, ElasticsearchTemplate elasticsearchTemplate) {
ElasticsearchPersistentEntity entity = elasticsearchTemplate.getPersistentEntityFor(cls);
try {
Field field = SimpleElasticsearchPersistentEntity.class.getDeclaredField("indexType");
field.setAccessible(true);
String indexDefault = field.get(entity).toString();
if (!StringUtils.isEmpty(type)) {
field.set(entity, type);
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
public class ESDynamicIndexRepository<T,D> {
@Autowired
private DynamicIndexElasticsearchTemplate dynamicIndexElasticsearchTemplate;
private Class<? extends Object> class1;
private CustomElasticsearchRepositoryFactory getFactory(ElasticsearchTemplate elasticsearchTemplate,String indexName,String indexType) {
CustomElasticsearchRepositoryFactory elasticFactory = new CustomElasticsearchRepositoryFactory(elasticsearchTemplate, indexName,indexType);
return elasticFactory;
}
@SuppressWarnings("unchecked")
private Class<T> resolveReturnedClassFromGenericType() {
ParameterizedType parameterizedType = resolveReturnedClassFromGenericType(getClass());
return (Class<T>) parameterizedType.getActualTypeArguments()[0];
}
private ParameterizedType resolveReturnedClassFromGenericType(Class<?> clazz) {
Object genericSuperclass = clazz.getGenericSuperclass();
if (genericSuperclass instanceof ParameterizedType) {
return (ParameterizedType) genericSuperclass;
}
return resolveReturnedClassFromGenericType(clazz.getSuperclass());
}
/**
* @param indexPrefix
* @param cls domain.class interview.class
* @return
*/
public ElasticsearchTemplate getElasticsearchTemplate(String indexPrefix,String indexType, Class cls) {
ElasticsearchTemplate esTemplate = dynamicIndexElasticsearchTemplate.getElasticsearchTemplate();
dynamicIndexElasticsearchTemplate.setIndex(indexPrefix, cls, esTemplate);
dynamicIndexElasticsearchTemplate.setType(indexPrefix, cls, esTemplate);
return esTemplate;
}
private Class<?> getClazz(Class proxy) {
Type[] types = proxy.getGenericInterfaces();
Type t1 = ((ParameterizedType) types[0]).getActualTypeArguments()[0];
return (Class) t1;
}
public T proxyRepository() {
return getProxyRepository(null,null,null);
}
public T getProxyRepository(String indexName,String indexType,D info) {
Class<T> proxy = resolveReturnedClassFromGenericType();
if (proxy.getClass().isInstance(ElasticsearchRepository.class)) {
ElasticsearchTemplate esTemplate = dynamicIndexElasticsearchTemplate.getElasticsearchTemplate();
Class<D> class_info= (Class<D>) info.getClass();
Document annotation = class_info.getAnnotation(Document.class);
Map mapping = esTemplate.getMapping(annotation.indexName(),annotation.type());
//动态处理索引需要的mapping结构,比如分词器什么的
handlerMapping(mapping,class_info);
ElasticsearchTemplate esTemplatenew = dynamicIndexElasticsearchTemplate.getElasticsearchTemplate();
if(!esTemplatenew.indexExists(indexName)){
//指定索引分片数量
esTemplatenew.getClient().admin().indices().prepareCreate(indexName)
.setSettings(Settings.builder()
.put("index.number_of_shards", 5)
.put("index.number_of_replicas", 1)
).get();
//刷新分片数量
esTemplatenew.getClient().admin().indices().prepareRefresh(indexName).get();
}
esTemplatenew.putMapping(indexName, indexType, mapping);
CustomElasticsearchRepositoryFactory esFactory = getFactory(esTemplatenew,indexName,indexType);
T proxyRepository = esFactory.getRepository(proxy);
if (!StringUtils.isEmpty(indexName)) {
dynamicIndexElasticsearchTemplate.setIndex(indexName, getClazz(proxy), esTemplatenew);
dynamicIndexElasticsearchTemplate.setType(indexType, getClazz(proxy), esTemplatenew);
}
return proxyRepository;
} else {
throw new RuntimeException("do not support thie proxy class");
}
}
/**
* 动态处理mapping
* @param mapping
* @param class_info
*/
@SuppressWarnings("rawtypes")
private void handlerMapping(Map mapping, Class<D> class_info) {
LinkedHashMap list = (LinkedHashMap) mapping.get("properties");
Field[] fields = class_info.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
String fieldname = fields[i].getName();
LinkedHashMap m = (LinkedHashMap) list.get(fieldname);
if(m==null){
continue;
}
if(m.containsKey("analyzer")){
//如果类型是text,满足既要支持分词查询,也要支持关键字查询,需要增加一个keyword类型,便于查询
m = handerUntouched(m,fieldname,"text");
}
//处理CodeChildrenInfo
if(class_info==CodeInfo.class){
if("nested".equals(m.get("type"))){
LinkedHashMap list_codevalue = (LinkedHashMap) m.get("properties");
Field[] fields_codevalue=null;
if("codeChildrenInfos".equals(fieldname)){
fields_codevalue = CodeChildrenInfo.class.getDeclaredFields();
}else if("codevalueInfos".equals(fieldname)){
fields_codevalue = CodeChildrenInfo.class.getDeclaredFields();
}
for (int j = 0; fields_codevalue!=null && j < fields_codevalue.length; j++) {
String fieldname_codevalue = fields_codevalue[j].getName();
LinkedHashMap m_codevalue = (LinkedHashMap) list_codevalue.get(fieldname_codevalue);
//如果类型是text,满足既要支持分词查询,也要支持关键字查询,需要增加一个keyword类型,便于查询
if(m_codevalue!=null ){
String type =StringUtils.toString(m_codevalue.get("type"));
if(!"keyword".equals(type)){
m_codevalue = handerUntouched(m_codevalue,fieldname_codevalue,type);
}
}
}
}
}
}
}
@SuppressWarnings("rawtypes")
public LinkedHashMap handerUntouched(LinkedHashMap m ,String fieldname,String defaulttype){
LinkedHashMap<String, Object> temp = new LinkedHashMap<String, Object>();
LinkedHashMap<String, Object> temp1 = new LinkedHashMap<String, Object>();
temp1.put("type",defaulttype);
temp1.put("store", "true");
temp1.put("index", true);
if("text".equals(defaulttype)){
temp1.put("analyzer", "ik_max_word");
temp1.put("search_analyzer", "ik_smart");
}
temp.put(fieldname, temp1);
Map<String, Object> temp2 = new HashMap<String, Object>();
temp2.put("type", "keyword");
temp2.put("store", "true");
temp2.put("index", true);
temp.put("untouched", temp2);
m.put("type", defaulttype);
m.put("fields",temp);
return m;
}
}
/**
* 接口关系:
* ElasticsearchRepository --> ElasticsearchCrudRepository --> PagingAndSortingRepository --> CrudRepository
* @param <T>
*/
@Repository
public interface CodeInfoRepository extends ElasticsearchRepository<CodeInfo , String> {
}
/**
基本索引字段bean,对应mapping结构
**/
@Document(indexName = "base_index_name",type = "index")
public class CodeInfo {
@ID
@Field(type = FieldType.Keyword,index=true,store=true)
private String codeid;
@Field(type = FieldType.Text, analyzer = "ik_max_word",searchAnalyzer="ik_smart",index=true,store=true)
private String desc1;
@Field(type = FieldType.Text, analyzer = "ik_max_word",searchAnalyzer="ik_smart",index=true,store=true)
private String desc2;
//子文档
@Field(type = FieldType.Nested,index = true,store=true)
private List<CodeChildrenInfo> codeChildrenInfos;
//......
//get和set方法
}
public class CodeChildrenInfo {
@ID
@Field(type = FieldType.Keyword,index=true,store=true)
private String codeChildrenid;
@Field(type = FieldType.Keyword,index=true,store=true)
private String codeid;
@Field(type = FieldType.Text, analyzer = "ik_max_word",searchAnalyzer="ik_smart",index=true,store=true)
private String desc1;
//......
//get和set方法
}
/**
定义连接9300的client,防止template模版串了,导致查询到别的索引的数据
**/
@Configuration
@EnableConfigurationProperties(ElasticsearchProperties.class)
public class ESTransportClient{
@value("${spring.data.elasticsearch.cluster-name:elasticsearch}")
private String clustername;
@value("${spring.data.elasticsearch.cluster-nodes:127.0.0.1:9300}")
private String clusternodes;
private TransportClient client=null;
private final ElasticsearchProperties properties;
public ESTransportClient(ElasticsearchProperties properties){
this.properties=properties;
}
@Bean
public TransportClient client(){
if(client!=null){
return client;
}else {
//建立连接
......
}
}
}