[hibernate-dev] Feature Proposal for Hibernate Search
Emmanuel Bernard
emmanuel at hibernate.org
Tue Feb 4 07:38:02 EST 2014
On Tue 2014-02-04 4:24, Martin Braun wrote:
> /**
> * @return a custom sort object or null
> */
> public Sort getSort();
>
>
> or how to facet, etc...
>
>
> I want for this stuff to move to annotations (maybe) because I don't really like
> the fact that I have to implement an Interface for that (and the current approach doesn't
> allow profiles).
Here is an half formed alternative idea that reverts your model.
class SomeQuery {
// some params as getter / setters
@Query(profile="a", forEntity=Customer.class)
public Query query(QueryBuilder qb) {
return qb.bool()
.must(
qb.keyword()
.onField("name")
.boostedTo(2f)
.matchingParameter("name")
.createQuery();
).createQuery(); //some other boolean query should be here
}
@Sort(profile="a")
Sort getSort() { ... }
...
}
session.createFullTextQuery(someQuery).list();
What this achieved is:
- all query info in one class
- support for multiple profiles
- reuse existing programmatic API
Probably some kind of interface would make more sense to propagate the
return type.
> > But annotations in my opinion don't scale very well for tree structures. Composition, lack of polymorphism are also not easy / elegant in annotations.
> > You can see that you had to break the sub queries with string references.
>
>
> I think they don't scale well in the general case but in this scenario I think it's ok.
>
>
> Look at this:
>
>
>
> @Queries(@Query(profile = "notName", must = @Must(subQuery = "someNameForTheQuery")))
> @SubQueries(@SubQuery(id = "someNameForTheQuery", query = @Query(must = @Must(not = true, value = @SearchField(fieldName = "name", propertyName = "name")))))
>
>
>
> I look at it this way: I lose the easy way to do tree structures, but I gain a way to document my query by having to give names to my sub-queries :).
I can document my subqueries by name using Java local variables :)
Query filterByName = qb.keyword().onField("name").matchingParameter("name").createQuery();
return qb.all().except(filterByName).createQuery();
BTW, I wonder why in your annotation approach all @Query are junction
queries. There is a small redundancy as the subquery defines a must not
in your example and the top query defines a must. What would happen if
the top query defined a @Should? Bootstrap error?
This is one of the things that throw off Hardy (I think) and me when we
look at the current annotations.
>
>
> > And I am not sure how you will be able to express other query types that we have like range, spatial etc. I might be wrong, so it's worth trying. But even then, if we had one new query type, we
> > have to also add an equivalent annotation or add new fields to an existing one.
>
>
>
> Uhm. I totally forgot to add this functionality in my rewrite (I have rewritten most of the code last weekend)
> and I implemented a way to pass parameters into QueryTypes. You can even pass parameters that are dynamically
> determined by stating the property to get its value from. With that you can easily do RangeQueryTypes.
> If you want me to elaborate on that, I can provide you with an example.
Yes :)
>
>
> > What do you mean by query nesting by hand?
>
>
> Consider you have a query like this (again with boolean syntax):
>
>
> (queryA || queryD) && (queryB || (queryC) || queryE,...
>
>
> Now you would have to build a BooleanJunction and several subJunctions
> and then put them together. I have written that type of code before and
> I made some mistakes because I messed up the variable names in my head.
>
>
> > And how does the annotation approach differs?
>
>
> In the annotation Version it would look something like this (example from above):
>
>
>
> @Queries(@Query(must = {
> @Must(subQuery = "queryAOrQueryD"),
> @Must(subQuery = "queryBOrQueryC"),
> @Must(subQuery = "queryE")}))
> @SubQueries({
> @SubQuery(id = "queryAOrQueryD",
> query = @Query(should = {@Should(subQuery = "queryA"), @Should(subQuery = "queryD")})
> @SubQuery(id = "queryBOrQueryC",
> query = @Query(should = {@Should(subQuery = "queryB"), @Should(subQuery = "queryC")})
> ...
> //define query[A-E] here.
> })
>
>
>
> Maybe it's because I don't like to work with the Junctions and put them together myself,
> and maybe it's only me that thinks this would be easier :P.
OK. BTW this is how I would write such query decomposing it. I would not
rely on the intermediary BooleanJunction object.
Query queryA = ...
Query queryB = ...
Query queryC = ...
Query queryD = ...
Query queryE = ...
qb.bool()
.must(
qb.bool().should(queryA).should(queryD).createQuery()
)
.must(
qb.bool().should(queryB).should(queryC).query(E).createQuery()
)
.must(
queryE
)
.createQuery();
More information about the hibernate-dev
mailing list