springboot elasticsearch 集成注意事項

  文章來源: http://www.cnblogs.com/guozp/p/8686904.html

一 elasticsearch基礎

   這裏假設各位已經簡單瞭解過elasticsearch,並不對es進入更多的,更深層次的解釋,若有必要,會在寫文章專門進行es講解。html

  Elasticsearch是一個基於Apache Lucene(TM)的開源搜索引擎。不管在開源仍是專有領域,Lucene能夠被認爲是迄今爲止最早進、性能最好的、功能最全的搜索引擎庫。java

  可是,Lucene只是一個庫。想要使用它,你必須使用Java來做爲開發語言並將其直接集成到你的應用中,更糟糕的是,Lucene很是複雜,你須要深刻了解檢索的相關知識來理解它是如何工做的。node

  Elasticsearch也使用Java開發並使用Lucene做爲其核心來實現全部索引和搜索的功能,可是它的目的是經過簡單的RESTful API來隱藏Lucene的複雜性,從而讓全文搜索變得簡單。mysql

   index ==》索引 ==》Mysql中的一個庫,庫裏面能夠創建不少表,存儲不一樣類型的數據,而表在ES中就是type。git

   type ==》類型 ==》至關於Mysql中的一張表,存儲json類型的數據github

   document  ==》文檔 ==》一個文檔至關於Mysql一行的數據算法

   field ==》列 ==》至關於mysql中的列,也就是一個屬性spring

 這裏多說下:sql

在Elasticsearch6.0.0或者或者更新版本中建立的索引只會包含一個映射類型(mappingtype)。在5.x中建立的具備多個映射類型的索引在Elasticsearch6.x中依然會正常工做。在Elasticsearch7.0.0中,映射類型type將會被徹底移除。數據庫

原文連接

  開始的時候,咱們說「索引(index)」相似於SQL數據庫中的「數據庫」,將「類型(type)」等同於「表」。

  這是一個糟糕的類比,而且致使了一些錯誤的假設。在SQL數據庫中,表之間是相互獨立的。一個表中的各列並不會影響到其它表中的同名的列。而在映射類型(mappingtype)中卻不是這樣的。

   在同一個Elasticsearch索引中,其中不一樣映射類型中的同名字段在內部是由同一個Lucene字段來支持的。換句話說,使用上面的例子,user類型中的user_name字段與tweet類型中的user_name字段是徹底同樣的,而且兩個user_name字段在兩個類型中必須具備相同的映射(定義)。

   這會在某些狀況下致使一些混亂,好比,在同一個索引中,當你想在其中的一個類型中將deleted字段做爲date類型,而在另外一個類型中將其做爲boolean字段。

   在此之上須要考慮一點,若是同一個索引中存儲的各個實體若是隻有不多或者根本沒有一樣的字段,這種狀況會致使稀疏數據,而且會影響到Lucene的高效壓縮數據的能力。

   基於這些緣由,將映射類型的概念從Elasticsearch中移除。

 

二 springboot 對應的Es版本關係

 

 

springboot  elasticsearch
2.0.0.RELEASE 2.2.0
1.4.0.M1 1.7.3
1.3.0.RELEASE 1.5.2
1.2.0.RELEASE 1.4.4
1.1.0.RELEASE 1.3.2
1.0.0.RELEASE 1.1.1

 

 

  一、None of the configured nodes are available 或者org.elasticsearch.transport.RemoteTransportException: Failed to deserialize exception response from stream

  緣由:spring data elasticSearch 的版本與Spring boot、Elasticsearch版本不匹配。

這是版本之間的對應關係。Spring boot 1.3.5默認的elasticsearch版本是1.5.2,此時啓動1.7.2版本如下的Elasticsearch客戶端鏈接正常。

  注:注意java的es默認鏈接端口是9300,9200是http端口,這兩個在使用中應注意區分。

  二、Caused by: java.lang.IllegalArgumentException: @ConditionalOnMissingBean annotations must specify at least one bean (type, name or annotation)

  緣由:spring boot是1.3.x版本,而es採用了2.x版本。在es的2.x版本去除了一些類,而這些類在spring boot的1.3.x版本中仍然被使用,致使此錯誤

    以上解決參考下面的對應關係

Spring Boot Version (x) Spring Data Elasticsearch Version (y) Elasticsearch Version (z)
x <= 1.3.5 y <= 1.3.4 z <= 1.7.2*
x >= 1.4.x 2.0.0 <=y < 5.0.0** 2.0.0 <= z < 5.0.0**

 

   請必定注意版本兼容問題。這關係到不少maven依賴。Spring Data Elasticsearch Spring Boot version matrix

 

ik 分詞對應的版本關係:

  elasticsearch-analysis-ik

 

Analyzer:

   ik_smart , ik_max_word , Tokenizer: ik_smart , ik_max_word

 

Versions

IK version ES version
master 6.x -> master
6.2.2 6.2.2
6.1.3 6.1.3
5.6.8 5.6.8
5.5.3 5.5.3
5.4.3 5.4.3
5.3.3 5.3.3
5.2.2 5.2.2
5.1.2 5.1.2
1.10.6 2.4.6
1.9.5 2.3.5
1.8.1 2.2.1
1.7.0 2.1.1
1.5.0 2.0.0
1.2.6 1.0.0
1.2.5 0.90.x
1.1.3 0.20.x
1.0.0 0.16.2 -> 0.19.0

 

 

三 環境構建

maven依賴:前提是依賴

<parent>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-parent</artifactId>
   <version>1.5.9.RELEASE</version>
   <relativePath/> <!-- lookup parent from repository -->
</parent>

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

配置文件:

# ES
#開啓 Elasticsearch 倉庫(默認值:true)
spring.data.elasticsearch.repositories.enabled=true
#默認 9300 是 Java 客戶端的端口。9200 是支持 Restful HTTP 的接口
spring.data.elasticsearch.cluster-nodes = 127.0.0.1:9300
#spring.data.elasticsearch.cluster-name Elasticsearch 集羣名(默認值: elasticsearch)
#spring.data.elasticsearch.cluster-nodes 集羣節點地址列表,用逗號分隔。若是沒有指定,就啓動一個客戶端節點
#spring.data.elasticsearch.propertie 用來配置客戶端的額外屬性
#存儲索引的位置
spring.data.elasticsearch.properties.path.home=/data/project/target/elastic
#鏈接超時的時間
spring.data.elasticsearch.properties.transport.tcp.connect_timeout=120s

  

 四 es索引實體類

Spring-data-elasticsearch爲咱們提供了@Document@Field等註解,若是某個實體須要創建索引,只須要加上這些註解便可

1.類上註解:@Document (至關於Hibernate實體的@Entity/@Table)(必寫),加上了@Document註解以後,默認狀況下這個實體中全部的屬性都會被創建索引、而且分詞。

類型 屬性名 默認值 說明
String indexName 索引庫的名稱,建議以項目的名稱命名
String type 「」 類型,建議以實體的名稱命名
short shards 5 默認分區數
short replica 1 每一個分區默認的備份數
String refreshInterval 「1s」 刷新間隔
String indexStoreType 「fs」 索引文件存儲類型

2.主鍵註解:@Id (至關於Hibernate實體的主鍵@Id註解)(必寫)

只是一個標識,並無屬性。

3.屬性註解 @Field (至關於Hibernate實體的@Column註解)

@Field默認是能夠不加的,默認全部屬性都會添加到ES中。加上@Field以後,@document默認把全部字段加上索引失效,只有家@Field 纔會被索引(同時也看設置索引的屬性是否爲no)

 

類型 屬性名 默認值 說明
FieldType type FieldType.Auto 自動檢測屬性的類型
FieldIndex index FieldIndex.analyzed 默認狀況下分詞
boolean store false 默認狀況下不存儲原文
String searchAnalyzer 「」 指定字段搜索時使用的分詞器
String indexAnalyzer 「」 指定字段創建索引時指定的分詞器
String[] ignoreFields {} 若是某個字段須要被忽略

 

五 相關查詢方法

 官網參考

  實現方式比較多,已經存在的接口,使用根據須要繼承便可:

  一、CrudRepository接口 

public interface CrudRepository<T, ID extends Serializable>
  extends Repository<T, ID> {

  <S extends T> S save(S entity);      

  Optional<T> findById(ID primaryKey); 

  Iterable<T> findAll();               

  long count();                        

  void delete(T entity);               

  boolean existsById(ID primaryKey);   

  // … more functionality omitted.
}

  二、PagingAndSortingRepository接口

 

public interface PagingAndSortingRepository<T, ID extends Serializable>
  extends CrudRepository<T, ID> {

  Iterable<T> findAll(Sort sort);

  Page<T> findAll(Pageable pageable);
}

 

 例子:

分頁:

PagingAndSortingRepository<User, Long> repository = // … get access to a bean
Page<User> users = repository.findAll(new PageRequest(1, 20));

 

計數:

interface UserRepository extends CrudRepository<User, Long> {

  long countByLastname(String lastname);
}  

  三、其餘,參考官網

  

  自定義查詢實現

那麼咱們如何自定義方法呢?咱們只要使用特定的單詞對方法名進行定義,那麼Spring就會對咱們寫的方法名進行解析, 

該機制條前綴find…Byread…Byquery…Bycount…By,和get…By從所述方法和開始分析它的其他部分。引入子句能夠包含進一步的表達式,如Distinct在要建立的查詢上設置不一樣的標誌。然而,第一個By做爲分隔符來指示實際標準的開始。在很是基礎的層次上,您能夠定義實體屬性的條件並將它們與And鏈接起來Or

interface PersonRepository extends Repository<User, Long> {

  List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);

  // Enables the distinct flag for the query
  List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);
  List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname);

  // Enabling ignoring case for an individual property
  List<Person> findByLastnameIgnoreCase(String lastname);
  // Enabling ignoring case for all suitable properties
  List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname);

  // Enabling static ORDER BY for a query
  List<Person> findByLastnameOrderByFirstnameAsc(String lastname);
  List<Person> findByLastnameOrderByFirstnameDesc(String lastname);
}

 

  構建查詢屬性算法原理

如上例所示。在查詢建立時,確保解析的屬性是託管類的屬性。可是,你也能夠經過遍歷嵌套屬性來定義約束。假設Person x有一個Address和 ZipCode在這種狀況下,方法名稱爲

List<Person> findByAddressZipCode(ZipCode zipCode);

 

建立屬性遍歷x.address.zipCode解析算法首先將整個part(AddressZipCode)做爲屬性進行解釋,而後檢查具備該名稱屬性的類。若是皮匹配成功,則使用該屬性。若是不是屬性,則算法拆分從右側的駝峯部分頭部和尾部,並試圖找出相應的屬性,在咱們的例子,AddressZipCode若是算法找到具備該頭部的屬性,它將採用尾部並繼續從那裏構建樹,而後按照剛剛描述的方式分割尾部。若是第一個分割不匹配,則算法將分割點移動到左側(AddressZipCode)並繼續。

雖然這應該適用於大多數狀況,但算法仍可能會選擇錯誤的屬性。假設這個Person類也有一個addressZip屬性。該算法將在第一輪拆分中匹配,而且基本上選擇錯誤的屬性並最終失敗(由於addressZip可能沒有code屬性的類型)。

爲了解決這個歧義,你能夠\_在你的方法名稱中使用手動定義遍歷點。因此咱們的方法名稱會像這樣結束:

List<Person> findByAddress_ZipCode(ZipCode zipCode);
因爲咱們將下劃線視爲保留字符,所以咱們強烈建議遵循標準的Java命名約定(即,不要在屬性名稱中使用下劃線,而應使用駝峯大小寫)

其餘分頁查詢

Page<User> findByLastname(String lastname, Pageable pageable);

Slice<User> findByLastname(String lastname, Pageable pageable);

List<User> findByLastname(String lastname, Sort sort);
 
  

  也能夠用Java8 Stream查詢和sql語句查詢

 
  
@Query("select u from User u")
Stream<User> findAllByCustomQueryAndStream();

Stream<User> readAllByFirstnameNotNull();

@Query("select u from User u")
Stream<User> streamAllPaged(Pageable pageable);
 
  

  有些在複雜的可使用es查詢語句

  咱們可使用@Query註解進行查詢,這樣要求咱們須要本身寫ES的查詢語句

  
public interface BookRepository extends ElasticsearchRepository<Book, String> {
    @Query("{"bool" : {"must" : {"field" : {"name" : "?0"}}}}")
    Page<Book> findByName(String name,Pageable pageable);
}
 
  

方法和es查詢轉換:

 
 
Keyword Sample Elasticsearch Query String

And

findByNameAndPrice

{"bool" : {"must" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}}

Or

findByNameOrPrice

{"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}}

Is

findByName

{"bool" : {"must" : {"field" : {"name" : "?"}}}}

Not

findByNameNot

{"bool" : {"must_not" : {"field" : {"name" : "?"}}}}

Between

findByPriceBetween

{"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}

LessThanEqual

findByPriceLessThan

{"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}

GreaterThanEqual

findByPriceGreaterThan

{"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}}

Before

findByPriceBefore

{"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}

After

findByPriceAfter

{"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}}

Like

findByNameLike

{"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}}

StartingWith

findByNameStartingWith

{"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}}

EndingWith

findByNameEndingWith

{"bool" : {"must" : {"field" : {"name" : {"query" : "*?","analyze_wildcard" : true}}}}}

Contains/Containing

findByNameContaining

{"bool" : {"must" : {"field" : {"name" : {"query" : "?","analyze_wildcard" : true}}}}}

In

findByNameIn(Collection<String>names)

{"bool" : {"must" : {"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"name" : "?"}} ]}}}}

NotIn

findByNameNotIn(Collection<String>names)

{"bool" : {"must_not" : {"bool" : {"should" : {"field" : {"name" : "?"}}}}}}

Near

findByStoreNear

Not Supported Yet !

True

findByAvailableTrue

{"bool" : {"must" : {"field" : {"available" : true}}}}

False

findByAvailableFalse

{"bool" : {"must" : {"field" : {"available" : false}}}}

OrderBy

findByAvailableTrueOrderByNameDesc

{"sort" : [{ "name" : {"order" : "desc"} }],"bool" : {"must" : {"field" : {"available" : true}}}}

 

 

六 between使用注意

  在使用的時候沒有找到直接的例子,因爲between是轉換成range,因此須要範圍參數from和to,

 舉例以下:

Page<Recruit> findByRecruitWorkAndRecruitCitysAndWorkTypeAndXjTimeBetween(String recruitWork, String recruitCitys, Integer workType, Date fromXjTime, Date toXjTime,Pageable pageable);

  注意:

  這裏必需要注意的是:只要使用了between參數,****XjTimeBetween(......,from,to) ,使用該方法的時候,必需要傳遞範圍參數from,to,不能同時爲空。

  不然異常

 

org.springframework.dao.InvalidDataAccessApiUsageException: Range [* TO *] is not allowed
	at org.springframework.data.elasticsearch.core.query.Criteria.between(Criteria.java:304)
	at org.springframework.data.elasticsearch.repository.query.parser.ElasticsearchQueryCreator.from(ElasticsearchQueryCreator.java:127)
	at org.springframework.data.elasticsearch.repository.query.parser.ElasticsearchQueryCreator.and(ElasticsearchQueryCreator.java:76)
	at org.springframework.data.elasticsearch.repository.query.parser.ElasticsearchQueryCreator.and(ElasticsearchQueryCreator.java:46)
	at org.springframework.data.repository.query.parser.AbstractQueryCreator.createCriteria(AbstractQueryCreator.java:109)
	at org.springframework.data.repository.query.parser.AbstractQueryCreator.createQuery(AbstractQueryCreator.java:88)
	at org.springframework.data.repository.query.parser.AbstractQueryCreator.createQuery(AbstractQueryCreator.java:73)
	at org.springframework.data.elasticsearch.repository.query.ElasticsearchPartQuery.createQuery(ElasticsearchPartQuery.java:102)
	at org.springframework.data.elasticsearch.repository.query.ElasticsearchPartQuery.execute(ElasticsearchPartQuery.java:51)
	at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:499)
	at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:477)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:56)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
	at com.sun.proxy.$Proxy86.findByRecruitWorkAndRecruitCitysAndWorkTypeAndXjTimeBetween(Unknown Source)
	at com.zhimingdeng.service.impl.EsIndexServiceImpl.findByRecruitWorkAndRecruitCitysAndWorkTypeAndXjTimeBetween(EsIndexServiceImpl.java:155)

  由於底層要求參數不能同時爲空

 

七  es時間類型注意

  來源: http://www.cnblogs.com/guozp/p/8686904.html 

   對於Elasticsearch原生支持date類型,json格式經過字符來表示date類型。因此在用json提交日期至elasticsearch的時候,es會隱式轉換,把es認爲是date類型的字符串直接轉爲date類型,間字段內容實際上就是轉換成long類型做爲內部存儲的(因此徹底能夠接受其餘時間格式做爲時間字段的內容)。至於什麼樣的字符串es會認爲能夠轉換成date類型參考elasticsearch官網介紹

  date類型是包含時區信息的,若是咱們沒有在json表明日期的字符串中顯式指定時區,對es來講沒什麼問題,可是對於咱們來講可能會發現一些時間差8個小時的問題。

  Elastic自己有一種特殊的時間格式,其形式如"2016-01-25T00:00:00",此格式爲ISO8601標準。具體時間日期格式要求能夠參見es官方文檔

  然而咱們在計算日期間隔,甚至按日分類的時候,每每須要把這個String時間轉化爲Unix時間戳(Unix Timestamp(時間戳))的形式,再進行計算。而一般,這個時間戳會以毫秒的形式(Java)保存在一個long類型裏面,這就涉及到了String與long類型的相互轉化。

  此外在使用Java Client聚合查詢日期的時候,須要注意時區問題,由於默認的es是按照UTC標準時區算的,因此不設置的聚合統計結果是不正確的。默認不設置時區參數,es是安裝UTC的時間進行查詢的,因此分組的結果可能與預期不同。  

  JSON 沒有日期類型,所以在 Elasticsearch 中能夠表達成:

 

  1. 日期格式化的字符串,好比: "2018-01-01" 或者 "2018/01/01 01:01:30";
  2. 毫秒級別的 long 類型或秒級別的 integer 類型,好比: 1515150699465, 1515150699;

 

  實際上無論日期以何種格式寫入,在 ES 內部都會先穿換成 UTC 時間並存儲爲 long 類型。日期格式能夠自定義,若是沒有指定的話會使用如下的默認格式:

  "strict_date_optional_time||epoch_millis"

 

  所以總結來講,無論哪一種能夠表示時間的格式寫入,均可以用來表示時間

 

  因此這裏引出多種解決方案:

   一、es 默認的是 utc 時間,而國內服務器是 cst 時間,首先有時間上的差距須要轉換。可是若是底層以及上層都統一用時間戳,完美解決時區問題。可是時間戳對咱們來講不直觀 

    
     時間範圍查找需求: 存儲Date,和取出來也是Dete

    存儲的時候利用各類JSON對象,如 Jackson 等。存儲的時候就能夠用JSON Format一下再存儲,而後取出來後

  @Field( type = FieldType.Date,
            format = DateFormat.custom,pattern = "yyyy-MM-dd HH:mm:ss" ) @JsonFormat (shape = JsonFormat.Shape.STRING, pattern ="yyyy-MM-dd HH:mm:ss",timezone="GMT+8") private Date xjTime;

     有了這個註解後,

    timezone="GMT+8" 主要是由於底層存放的數據日期時區是UTC,這裏轉換成GMT

    真實存儲格式以下(高能瞎眼):

     時間範圍查找需求注意:

    根據條件查詢的時候,時間範圍須要傳入range,這裏涉及到了兩種選擇,底層查詢方法實現的時候range的參數爲

    1 date:

      傳入的是date參數,而後就行查詢的時候,會報異常,由於我把日期轉成了yyyy-MM-dd HH:mm:ss,可是底層數據是2018-03-27T16:00:00.000Z這種格式,致使錯誤,詳細異常以下

org.elasticsearch.action.search.SearchPhaseExecutionException: all shards failed
	at org.elasticsearch.action.search.AbstractSearchAsyncAction.onFirstPhaseResult(AbstractSearchAsyncAction.java:206)
	at org.elasticsearch.action.search.AbstractSearchAsyncAction$1.onFailure(AbstractSearchAsyncAction.java:152)
	at org.elasticsearch.action.ActionListenerResponseHandler.handleException(ActionListenerResponseHandler.java:46)
	at org.elasticsearch.transport.TransportService$DirectResponseChannel.processException(TransportService.java:855)
	at org.elasticsearch.transport.TransportService$DirectResponseChannel.sendResponse(TransportService.java:833)
	at org.elasticsearch.transport.TransportService$4.onFailure(TransportService.java:387)
	at org.elasticsearch.common.util.concurrent.AbstractRunnable.run(AbstractRunnable.java:39)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
Caused by: org.elasticsearch.ElasticsearchParseException: failed to parse date field [2018-03-27T16:00:00.000Z] with format [yyyy-MM-dd HH:mm:ss]
	at org.elasticsearch.common.joda.DateMathParser.parseDateTime(DateMathParser.java:203)
	at org.elasticsearch.common.joda.DateMathParser.parse(DateMathParser.java:67)
	at org.elasticsearch.index.mapper.core.DateFieldMapper$DateFieldType.parseToMilliseconds(DateFieldMapper.java:451)
	at org.elasticsearch.index.mapper.core.DateFieldMapper$DateFieldType.innerRangeQuery(DateFieldMapper.java:435)
	at org.elasticsearch.index.mapper.core.DateFieldMapper$DateFieldType.access$000(DateFieldMapper.java:199)
	at org.elasticsearch.index.mapper.core.DateFieldMapper$DateFieldType$LateParsingQuery.rewrite(DateFieldMapper.java:224)
	at org.apache.lucene.search.BooleanQuery.rewrite(BooleanQuery.java:278)
	at org.apache.lucene.search.IndexSearcher.rewrite(IndexSearcher.java:837)
	at org.elasticsearch.search.internal.ContextIndexSearcher.rewrite(ContextIndexSearcher.java:81)
	at org.elasticsearch.search.internal.DefaultSearchContext.preProcess(DefaultSearchContext.java:231)
	at org.elasticsearch.search.query.QueryPhase.preProcess(QueryPhase.java:103)
	at org.elasticsearch.search.SearchService.createContext(SearchService.java:676)
	at org.elasticsearch.search.SearchService.createAndPutContext(SearchService.java:620)
	at org.elasticsearch.search.SearchService.executeDfsPhase(SearchService.java:264)
	at org.elasticsearch.search.action.SearchServiceTransportAction$SearchDfsTransportHandler.messageReceived(SearchServiceTransportAction.java:360)
	at org.elasticsearch.search.action.SearchServiceTransportAction$SearchDfsTransportHandler.messageReceived(SearchServiceTransportAction.java:357)
	at org.elasticsearch.transport.TransportRequestHandler.messageReceived(TransportRequestHandler.java:33)
	at org.elasticsearch.transport.RequestHandlerRegistry.processMessageReceived(RequestHandlerRegistry.java:75)
	at org.elasticsearch.transport.TransportService$4.doRun(TransportService.java:376)
	at org.elasticsearch.common.util.concurrent.AbstractRunnable.run(AbstractRunnable.java:37)
	... 3 common frames omitted
Caused by: java.lang.IllegalArgumentException: Invalid format: "2018-03-27T16:00:00.000Z" is malformed at "T16:00:00.000Z"
	at org.joda.time.format.DateTimeParserBucket.doParseMillis(DateTimeParserBucket.java:187)
	at org.joda.time.format.DateTimeFormatter.parseMillis(DateTimeFormatter.java:826)
	at org.elasticsearch.common.joda.DateMathParser.parseDateTime(DateMathParser.java:200)
	... 22 common frames omitted

解決:

  傳入的date參數格式化成底層的類型  

實現參考:

Page<Recruit> findByRecruitWorkAndRecruitCitysAndWorkTypeAndXjTimeBetween(String recruitWork, String recruitCitys, Integer workType, Date fromXjTime, Date toXjTime,Pageable pageable);

 

   

 2 String

     參數直接使用string,避免上層轉換成不合適的時間格式,使用框架底層本身轉換,避免錯誤。

  實現參考:

  

實現參考:
Page<Recruit> findByRecruitWorkAndRecruitCitysAndWorkTypeAndXjTimeBetween(String recruitWork, String recruitCitys, Integer workType, String fromXjTime, String toXjTime,Pageable pageable);
 
 

    

es時間自定義類型

https://stackoverflow.com/questions/29122071/elasticsearch-failed-to-parse-date

https://stackoverflow.com/questions/29496081/spring-data-elasticsearchs-field-annotation-not-working

https://stackoverflow.com/questions/32042430/elasticsearch-spring-data-date-format-always-is-long

八 使用注意

  我的認爲springboot 這種集成es的方法,最大的優勢是開發速度快,不要求對es一些api要求熟悉,能快速上手,即便以前對es不勝瞭解,也能經過方法名或者sql快速寫出本身須要的邏輯,而具體轉換成api層的操做,則有框架底層幫你實現。

  缺點也顯而易見首先,使用的springboot的版本對es的版本也有了要求,不能超過es的某些版本號,部署時須要注意。第二,速度提高的同時,也失去了一些實用api的靈活性。一些比較靈活的條件封裝不能很容易的實現。各有利弊,各位權衡

  來源: http://www.cnblogs.com/guozp/p/8686904.html 

相關文章
相關標籤/搜索