如何过滤多个字段的搜索查询?
How to filter a search query on multiple fields?
我有一份学习清单。我想在首页使用预输入功能搜索它们。
为此,我将 Hibernate Search 与 Spring Boot (2.1.5) 一起使用。
我为我的 STUDY table 建立了索引,一些字段标有 @Field
属性以供索引。
搜索效果很好。
但现在我想添加一个过滤器来使用相同的预输入功能,但搜索我的研究的一个子集。
为此,我创建了一个类似于 Hibernate Search 文档的过滤器,但我没有找到一种方法来过滤两个字段之间的 OR。
我的实际过滤器,但只在一个字段上过滤 (avisDefinitifCet
):
/**
* etudeFilter
*/
public class EtudeFilterFactory {
private String clasCet1ErPassage;
private String avisDefinitifCet;
public void setClasCet1ErPassage(String clasCet1ErPassage) {
this.clasCet1ErPassage = clasCet1ErPassage;
}
public void setAvisDefinitifCet(String avisDefinitifCet) {
this.avisDefinitifCet = avisDefinitifCet;
}
@Factory
public Query getFilter() {
System.out.println("Filter avisDefinitifCet : " + this.avisDefinitifCet.toLowerCase());
return new TermQuery(new Term("avisDefinitifCet", this.avisDefinitifCet.toLowerCase()));
}
}
如何在我的案例中使用第二个字段进行过滤 clasCet1ErPassage
?
在这一端搜索标准搜索查询并像这样应用过滤器
SELECT *
FROM STUDY
WHERE
A=t OR B=t OR C=t -- Normal search
AND (avisDefinitifCet='acceptation' OR clasCet1ErPassage='acceptation') -- Filter on two fields
我的搜索功能:
public List<Etude> search(String text, Map<String, String> allParams) {
text = stripAccents(text);
// get the full text entity manager
FullTextEntityManager fullTextEntityManager = getFullTextEntityManager(entityManager);
// create the query using Hibernate Search query DSL
QueryBuilder queryBuilder = fullTextEntityManager
.getSearchFactory()
.buildQueryBuilder()
.forEntity(Etude.class)
.get();
// Simple Query String queries
Query query = queryBuilder
.simpleQueryString()
.onFields("n0Cet")
.andField("anneeCet")
.andField("noDansAnneeCet")
.andField("sigleEtude")
.andField("titreEtude")
.andField("traitement1")
.andField("traitement2")
.andField("traitement3")
.andField("traitement4")
.andField("traitement5")
.andField("demandeurIgr.nomInvestigateurIgr")
.andField("investigateurHorsIgr.nomInvestigateur")
.andField("investigateurIgr.nomInvestigateurIgr")
.andField("promoteur.nomPromoteur")
.matching(text)
.createQuery();
// wrap Lucene query in an Hibernate Query object
FullTextQuery fullTextQuery = fullTextEntityManager
.createFullTextQuery(query, Etude.class)
.setMaxResults(101);
// Here allParams contains
// avisDefinitifCet => 'acceptation',
// clasCet1ErPassage => 'acceptation'
allParams.forEach((key, value) -> {
fullTextQuery.enableFullTextFilter("etudeFilter").setParameter(key, value);
});
return (List<Etude>) fullTextQuery.getResultList();
}
我是在以正确的方式思考实施它还是我做错了?
编辑:显然您正在使用 full-text 过滤器,您确实必须直接使用 Lucene API。
在这种情况下,只需使用带有 "should" 子句的布尔连接。当布尔连接中只有 "should" 个子句时,至少其中一个必须匹配。
@Factory
public Query getFilter() {
String valueToMatch = this.avisDefinitifCet.toLowerCase();
return new BooleanQuery.Builder()
.add(new TermQuery(new Term("avisDefinitifCet", valueToMatch)), Occur.SHOULD)
.add(new TermQuery(new Term("clasCet1ErPassage", valueToMatch)), Occur.SHOULD)
.build();
}
上一个回答:
如果您是 Lucene 的新手,您真的应该尝试一下 Hibernate Search DSL。
在您的情况下,您需要一个针对两个字段的 keyword query:
EntityManager em = ...;
FullTextEntityManager fullTextEntityManager =
org.hibernate.search.jpa.Search.getFullTextEntityManager(em);
QueryBuilder queryBuilder = fullTextEntityManager.getSearchFactory()
.buildQueryBuilder().forEntity( Etude.class ).get();
Query luceneQuery = queryBuilder.keyword()
.onField("avisDefinitifCet").andField("clasCet1ErPassage")
.matching("acceptation")
.createQuery();
请注意,尽管调用了方法 andField
,它实际上是一个 "OR":如果任何字段匹配,查询将匹配。
有关更高级的查询组合,请查看 boolean junctions。
感谢@yrodiere
,这是我用来解决问题的方法
@Factory
public Query getFilter() {
return new BooleanQuery.Builder()
.add(new TermQuery(new Term("avisDefinitifCet", this.avisDefinitifCet.toLowerCase())), BooleanClause.Occur.SHOULD)
.add(new TermQuery(new Term("clasCet1ErPassage", this.clasCet1ErPassage.toLowerCase())), BooleanClause.Occur.SHOULD)
.build();
}
我有一份学习清单。我想在首页使用预输入功能搜索它们。
为此,我将 Hibernate Search 与 Spring Boot (2.1.5) 一起使用。
我为我的 STUDY table 建立了索引,一些字段标有 @Field
属性以供索引。
搜索效果很好。
但现在我想添加一个过滤器来使用相同的预输入功能,但搜索我的研究的一个子集。
为此,我创建了一个类似于 Hibernate Search 文档的过滤器,但我没有找到一种方法来过滤两个字段之间的 OR。
我的实际过滤器,但只在一个字段上过滤 (avisDefinitifCet
):
/**
* etudeFilter
*/
public class EtudeFilterFactory {
private String clasCet1ErPassage;
private String avisDefinitifCet;
public void setClasCet1ErPassage(String clasCet1ErPassage) {
this.clasCet1ErPassage = clasCet1ErPassage;
}
public void setAvisDefinitifCet(String avisDefinitifCet) {
this.avisDefinitifCet = avisDefinitifCet;
}
@Factory
public Query getFilter() {
System.out.println("Filter avisDefinitifCet : " + this.avisDefinitifCet.toLowerCase());
return new TermQuery(new Term("avisDefinitifCet", this.avisDefinitifCet.toLowerCase()));
}
}
如何在我的案例中使用第二个字段进行过滤 clasCet1ErPassage
?
在这一端搜索标准搜索查询并像这样应用过滤器
SELECT *
FROM STUDY
WHERE
A=t OR B=t OR C=t -- Normal search
AND (avisDefinitifCet='acceptation' OR clasCet1ErPassage='acceptation') -- Filter on two fields
我的搜索功能:
public List<Etude> search(String text, Map<String, String> allParams) {
text = stripAccents(text);
// get the full text entity manager
FullTextEntityManager fullTextEntityManager = getFullTextEntityManager(entityManager);
// create the query using Hibernate Search query DSL
QueryBuilder queryBuilder = fullTextEntityManager
.getSearchFactory()
.buildQueryBuilder()
.forEntity(Etude.class)
.get();
// Simple Query String queries
Query query = queryBuilder
.simpleQueryString()
.onFields("n0Cet")
.andField("anneeCet")
.andField("noDansAnneeCet")
.andField("sigleEtude")
.andField("titreEtude")
.andField("traitement1")
.andField("traitement2")
.andField("traitement3")
.andField("traitement4")
.andField("traitement5")
.andField("demandeurIgr.nomInvestigateurIgr")
.andField("investigateurHorsIgr.nomInvestigateur")
.andField("investigateurIgr.nomInvestigateurIgr")
.andField("promoteur.nomPromoteur")
.matching(text)
.createQuery();
// wrap Lucene query in an Hibernate Query object
FullTextQuery fullTextQuery = fullTextEntityManager
.createFullTextQuery(query, Etude.class)
.setMaxResults(101);
// Here allParams contains
// avisDefinitifCet => 'acceptation',
// clasCet1ErPassage => 'acceptation'
allParams.forEach((key, value) -> {
fullTextQuery.enableFullTextFilter("etudeFilter").setParameter(key, value);
});
return (List<Etude>) fullTextQuery.getResultList();
}
我是在以正确的方式思考实施它还是我做错了?
编辑:显然您正在使用 full-text 过滤器,您确实必须直接使用 Lucene API。
在这种情况下,只需使用带有 "should" 子句的布尔连接。当布尔连接中只有 "should" 个子句时,至少其中一个必须匹配。
@Factory
public Query getFilter() {
String valueToMatch = this.avisDefinitifCet.toLowerCase();
return new BooleanQuery.Builder()
.add(new TermQuery(new Term("avisDefinitifCet", valueToMatch)), Occur.SHOULD)
.add(new TermQuery(new Term("clasCet1ErPassage", valueToMatch)), Occur.SHOULD)
.build();
}
上一个回答:
如果您是 Lucene 的新手,您真的应该尝试一下 Hibernate Search DSL。
在您的情况下,您需要一个针对两个字段的 keyword query:
EntityManager em = ...;
FullTextEntityManager fullTextEntityManager =
org.hibernate.search.jpa.Search.getFullTextEntityManager(em);
QueryBuilder queryBuilder = fullTextEntityManager.getSearchFactory()
.buildQueryBuilder().forEntity( Etude.class ).get();
Query luceneQuery = queryBuilder.keyword()
.onField("avisDefinitifCet").andField("clasCet1ErPassage")
.matching("acceptation")
.createQuery();
请注意,尽管调用了方法 andField
,它实际上是一个 "OR":如果任何字段匹配,查询将匹配。
有关更高级的查询组合,请查看 boolean junctions。
感谢@yrodiere
,这是我用来解决问题的方法@Factory
public Query getFilter() {
return new BooleanQuery.Builder()
.add(new TermQuery(new Term("avisDefinitifCet", this.avisDefinitifCet.toLowerCase())), BooleanClause.Occur.SHOULD)
.add(new TermQuery(new Term("clasCet1ErPassage", this.clasCet1ErPassage.toLowerCase())), BooleanClause.Occur.SHOULD)
.build();
}