假設我有一個包含許多不同物體的應用程式,它們之間沒有關系。
我想創建一個查詢所有這些的搜索,但回傳一個統一的型別,即:
class SearchResult {
String stype;
String title;
String teaser;
}
所以我的想法是索引物體并將它們的值放入一個單一的索引(具有相同的索引欄位):
@Indexed(index = "idx_search")
class Book {
@Field(name = "stype", analyze = ...)
final String stype = "BOOK";
@Field(name = "title", analyze = ...)
String bookTitle;
@Field(name = "teaser", analyze = ...)
String bookBlurb ;
}
@Indexed(index = "idx_search")
class Person{
@Field(name = "stype", analyze = ...)
final String stype = "PERSON";
@Field(name = "title", analyze = ...)
String fullname;
@Field(name = "teaser", analyze = ...)
String profileIntroText;
}
@Indexed(index = "idx_search")
class Location{
@Field(name = "stype", analyze = ...)
final String stype = "LOCATION";
@Field(name = "title", analyze = ...)
String streetPcAndCity;
@Field(name = "teaser", analyze = ...)
String wikiIntoText;
}
如您所見,所有物體的索引名稱和欄位名稱都相同。
現在我想查詢他們得到這樣的結果:
SearchResult[stype: PERSON, title: Spongebob, teaser: A funny sponge]
SearchResult[stype: BOOK, title: Clean Architecture , teaser: A Craftsmans Guide to Software...]
SearchResult[stype: PERSON, title: Patric, teaser: A funny seastar]
SearchResult[stype: LOCATION, title: Hannover, teaser: A city in Germany]
所以 SearchResult 不是一個物體,而只是將結果合并為一個型別。索引作業,但我必須在搜索時將物體型別傳遞到查詢和 QueryBuilder 中:
final QueryBuilder queryBuilder = fullTextEntityManager
.getSearchFactory()
.buildQueryBuilder()
.forEntity(SearchResult.class)
.get();
...
Hibernate 然后回傳此錯誤訊息:
HSEARCH000331: Can't build query for type 'SearchResult' which is neither configured nor has any configured sub-types.
你認為這有辦法使這項作業嗎?
uj5u.com熱心網友回復:
請注意,您不需要將每個型別分配給相同的索引;Hibernate Search 完全能夠在單個查詢中搜索多個索引。并且性能可能是相同的(無論如何,Lucene 索引通常被分成多個部分)。
話雖如此,假設在 中有一個建構式,您可以這樣做SearchResult:
class SearchResult {
String stype;
String title;
String teaser;
public SearchResult(String stype, String title, String teaser) {
this.stype = stype;
this.title = title;
this.teaser = teaser;
}
}
FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager( entityManager);
final QueryBuilder queryBuilder = fullTextEntityManager
.getSearchFactory()
.buildQueryBuilder()
.forEntity(Book.class)
.get();
Query luceneQuery = ...;
FullTextQuery query = fullTextEntityManager.createFullTextQuery(query, Book.class, Person.class, Location.class);
query.setProjection("stype", "title", "teaser");
query.setMaxResults(20);
List<Object[]> arrayResults = query.list();
List<SearchResult> hits = new ArrayList<>();
for (Object[] array : arrayResults) {
hits.add(new SearchResult((String) array[0], (String) array[1], (String) array[2]);
}
另請注意,如果您升級到Hibernate Search 6,這可能會大大減少尷尬。
您需要對映射進行一些更改:
@Indexed
class Book {
@KeywordField(name = "stype")
@IndexingDependency(reindexOnUpdate = ReindexOnUpdate.NO)
final String stype = "BOOK";
@FullTextField(name = "title", analyzer = ...)
String bookTitle;
@FullTextField(name = "teaser", analyzer = ...)
String bookBlurb ;
}
@Indexed
class Person{
@KeywordField(name = "stype")
@IndexingDependency(reindexOnUpdate = ReindexOnUpdate.NO)
final String stype = "PERSON";
@FullTextField(name = "title", analyzer = ...)
String fullname;
@FullTextField(name = "teaser", analyzer = ...)
String profileIntroText;
}
@Indexed
class Location{
@KeywordField(name = "stype")
@IndexingDependency(reindexOnUpdate = ReindexOnUpdate.NO)
final String stype = "LOCATION";
@FullTextField(name = "title", analyzer = ...)
String streetPcAndCity;
@FullTextField(name = "teaser", analyzer = ...)
String wikiIntoText;
}
但是我認為搜索時的改進值得麻煩:
List<SearchResult> hits = Search.session(entityManager)
.search(Book.class, Person.class, Location.class)
.select(f -> f.composite(
SearchResult::new,
f.field("stype", String.class),
f.field("title", String.class),
f.field("teaser", String.class)))
.where(f -> ...)
.fetchHits( 20 );
在 Hibernate Search 6 中,你甚至可以使用一個介面:
interface Searchable {
@KeywordField(analyzer = ...)
String getStype();
@FullTextField(analyzer = ...)
String getTitle();
@FullTextField(analyzer = ...)
String getTeaser();
}
@Indexed
class Book implements Searchable {
String bookTitle;
String bookBlurb;
@Override
@javax.persistence.Transient
@IndexingDependency(reindexOnUpdate = ReindexOnUpdate.NO)
String getStype() {
return "BOOK";
}
@Override
@javax.persistence.Transient
@IndexingDependency(derivedFrom = @ObjectPath(
@PropertyValue(propertyName = "bookTitle")
))
String getTitle() {
return bookTitle;
}
@Override
@javax.persistence.Transient
@IndexingDependency(derivedFrom = @ObjectPath(
@PropertyValue(propertyName = "bookTitle")
))
String getTeaser() {
return bookBlurb;
}
}
@Indexed
class Person implements Searchable {
String fullname;
String profileIntroText;
@Override
@javax.persistence.Transient
@IndexingDependency(reindexOnUpdate = ReindexOnUpdate.NO)
String getStype() {
return "PERSON";
}
@Override
@javax.persistence.Transient
@IndexingDependency(derivedFrom = @ObjectPath(
@PropertyValue(propertyName = "bookTitle")
))
String getTitle() {
return bookTitle;
}
@Override
@javax.persistence.Transient
@IndexingDependency(derivedFrom = @ObjectPath(
@PropertyValue(propertyName = "bookTitle")
))
String getTeaser() {
return bookBlurb;
}
}
@Indexed
class Location implements Searchable {
String streetPcAndCity;
String wikiIntoText;
@Override
@javax.persistence.Transient
@IndexingDependency(reindexOnUpdate = ReindexOnUpdate.NO)
String getStype() {
return "LOCATION";
}
@Override
@javax.persistence.Transient
@IndexingDependency(derivedFrom = @ObjectPath(
@PropertyValue(propertyName = "streetPcAndCity")
))
String getTitle() {
return streetPcAndCity;
}
@Override
@javax.persistence.Transient
@IndexingDependency(derivedFrom = @ObjectPath(
@PropertyValue(propertyName = "wikiIntoText")
))
String getTeaser() {
return wikiIntoText;
}
}
然后你可以這樣搜索:
List<SearchResult> hits = Search.session(entityManager)
.search(Searchable.class)
.select(f -> f.composite(
SearchResult::new,
f.field("stype", String.class),
f.field("title", String.class),
f.field("teaser", String.class)))
.where(f -> ...)
.fetchHits( 20 );
或者,您可以直接加載物體:
List<Searchable> hits = Search.session(entityManager)
.search(Searchable.class)
.where(f -> ...)
.fetchHits( 20 );
for (Searchable hit : hits) {
String stype = hit.getStype();
String title = hit.getTitle();
String teaser = hit.getTeaser();
if ( hit instanceof Book ) {
...
}
else if ( hit instanceof Location ) {
...
}
else {
...
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/338266.html
