Query that returns only certain fields? - java

I've got a very large, structured document(s) stored in MongoDB, and am using Morphia to query and model it in Java. I'd like to write a query that only returns a handful of the fields in that document, rather than returning the entire thing. I've looked in the documentation on the Morphia site, but couldn't find anything that explains how to do this. Is it possible to write a query like this with Morphia? In pseudocode it would be something like
GET doc.propertyA, doc.propertyB, doc.propertyX FROM doc WHERE doc.someOtherProperty = 'Foo'
Thoughts? Or is Morphia not designed to operate in this manner? Is there something better I could try?

Take a look at this: https://rawgithub.com/wiki/mongodb/morphia/javadoc/0.103/apidocs/com/google/code/morphia/query/Query.html#retrievedFields%28boolean,%20java.lang.String...%29
You'll still get back your entity objects but they'll only contain the fields listed.

example is better than words.
Query returns only "_id" field.
datastore.createQuery(entityClazz.class).retrievedFields(true, Mapper.ID_KEY);

Related

Hibernate search: Indexed data with Ngram filter and while searching it gives incorrect result due to tokenizing while querying

I have an analyzer with this configuration,
searchMapping//
.analyzerDef(BaseEntity.CUSTOM_SEARCH_INDEX_ANALYZER, WhitespaceTokenizerFactory.class)//
.filter(LowerCaseFilterFactory.class)//
.filter(ASCIIFoldingFilterFactory.class)//
.filter(NGramFilterFactory.class).param("minGramSize", "1").param("maxGramSize", "200");
This is how my entity field is configured
#Field(analyzer = #Analyzer(definition = CUSTOM_SEARCH_INDEX_ANALYZER))
private String bookName;
This is how I create a search query
queryBuilder.keyword().onField(prefixedPath).matching(matchingString).createQuery()
I have an entity with value bookName="Gulliver" and another entity with bookName="xGulliver";
If I tried to search with data bookName = xG then am getting both entities where I would expect entity only with bookName="xGulliver";
Also looked on the query that is produced by hibernate-search.
Executing Lucene query '+(+(+(+(
bookName:x
bookName:xg
bookName:g))))
Above Lucene query is prepared using BooleanJunction::must conditions by Lucene I guess which means it should match all the conditions.
Still why its giving me both entity data. I dont understand here.
I can also override the analyzer while querying by having KeywordTokenizer instead of NGramFilterFactory but this is like I have to override for each and every field before creating QueryBuilder which doesnt looks good because then I have to override all index fields which I have about 100 fields and some are dynamic fields and I create individual query for each field.
Is there any other way to override the analyzer in 5.11 version or is it handled in some other way in hibernate-search 6.x version in easier way?
Hibernate versions that I use are,
hibernate-search-elasticsearch, hibernate-search-orm = 5.11.4.Final
Above Lucene query is prepared using BooleanJunction::must conditions by Lucene I guess which means it should match all the conditions. Still why its giving me both entity data. I dont understand here.
When you create a keyword query using Hibernate Search, the string passed to that query is analyzed, and if there are multiple tokens, Hibernate Search creates a boolean query with one "should" clause for each token. You can see it here " bookName:x bookName:xg bookName:g": there is no "+" sign before "bookName", which means those are not "must" clauses, they are "should" clauses.
I can also override the analyzer while querying by having KeywordTokenizer instead of NGramFilterFactory but this is like I have to override for each and every field before creating QueryBuilder which doesnt looks good because then I have to override all index fields which I have about 100 fields and some are dynamic fields and I create individual query for each field.
True, that's annoying.
Is there any other way to override the analyzer in 5.11 version
In 5.11, I don't think there is any other way to override analyzers.
If necessary and if you're using the Lucene backend, I believe you should be able to bypass the Hibernate Search DSL just for this specific query:
Get the analyzer you want: something like Analyzer analyzer = fullTextSession.getSearchFactory().getAnalyzer("myAnalyzerWithoutNGramTokenFilter").
Analyze the search terms: call analyzer.tokenStream(...) and use the TokenStream as appropriate. You'll get a list of tokens.
Create the Lucene Query: essentially it will be a boolean query with one TermQuery for each token.
Pass the resulting Query to Hibernate Search as usual.
or is it handled in some other way in hibernate-search 6.x version in easier way?
It's dead simple in Hibernate Search 6.0.0.Beta4. There are two solutions:
Implicitly: in your mapping, you can specify not only an analyzer (using #FullTextField(analyzer = "myAnalyzer")), but also a "search" analyzer using #FullTextField(analyzer = "myAnalyzer", searchAnalyzer = "mySearchAnalyzer"). The "default" analyzer will be used when indexing, while the "search" analyzer will be used when searching (querying).
Explicitly: at query time, you can override the analyzer on a given predicate by calling .analyzer("mySearchAnalyzer") while building the predicate. There is one example in this section of the documentation.
Note however that dynamic fields are not supported yet in Hibernate Search 6: HSEARCH-3273.

Using Jooq with jsonb_agg on postgreSQL without code generator?

I would like to use Jooq with jsonb_agg in order to create jsonb objects I can read as a stream. Is there a way to do this without having Jooq look at the database?
I know I can have Jooq look at the database and decide what aggregates it finds but is there a way to use this without going through that introspection process? I have been through the docs 4 times and don't see an answer.
So the answer is buried in the DSL documentation, regarding defining fields.
All of the examples before use some variant of:
create.select(field("example1"), field("example2")).from(table(a)...
However you can define your own fields or even inline function definitions.
A field definition could be something like:
Field<Object> example1 = field("example1");
Or if you want to define a type:
Field<String> example2 = field("example2", String.class);
This becomes important when you want to define more complex fields, such as:
Field<String> jsonAry = function("jsonb_agg", String.class, example2);
Jooq really shines at allowing things to be composed like this. You can then:
Fiend<String> fullJson = function("jsonb_build_object", String.class, example1, example2);
Then if you groupBy(example1) you get a nice jsonb_agg object out.

Hibernate search - '%like%' type query

I'm using hibernate-search in my Spring MVC project and I would like to accomplish something but I'm not sure if it's possible. Here is the problem:
I'm using NGramFilterFactoryClass for this and have configured minGramSize=3 and maxGramSize=3.
Let's say my search term is "Keyword"
If I type anything like this:
"ywo", "key", "ord", "blablaordblabla"
query will return "Keyword". This is fine and I understand how this works but what I wanna do is when I type something like:
"bkey", "blablaordblabla"
I don't want to return "Keyword". "Keyword" should be returned only when search term is something like:
"key", "ord", "ywo", "eywo", "word" etc...
So, I guess I'm looking for a '%like%' type query. How can I accomplish this with hinernate-search?
I don't know if is what you are looking for, but maybe you need what is called "wildcard queries".
Try to have a look at this link as reference.
Also have a look at this stackoverflow topic
If you Analyze your input with NGrams you won't be able to perform exact "Like%" queries.
You probably want a SimpleAnalyzer or something similar which doesn't completely break your keywords in smaller pieces, or you might want to skip Analysis for this field and index it as-is.
You then combine this with a WildCard Query; note how example in the reference docs uses the keyword element to build the query, which inherently disables the analyzer on the input. (Make sure you scroll down the the Wildcard queries section in the docs).
I assume you're using NGrams because you need them for another use case. Remember you can use the #Fields annotation to index a same property in various different ways, so you could index it with ngrams and also in another form more suited for wildcard queries.

How to use clause in order in Hibernate

I would like to get objects via Hibernate from database with concrete order. This order is something like that:
as the first I would like to get objects with column titled for example first_column not null,
as the second I would like to get objects with column second_column not null,
as the last I would like to get objects which third_column is the id for another object/table, and this another object has a field with concrete value for example: "something".
I have created criteria in this way:
criteria.addOrder(Order.asc("firstColumn"));
criteria.addOrder(Order.asc("secondColumn"));
but how can I meet the last requirement?
With the restriction I can do something like that:
criteria.createAlias("thirdColumn", "t");
criteria.add(Restrictions.eq("t.field", "something"));
But I have to use order, not restriction with three separate Criteria results, because I am using also setFirstResult() and setMaxResults() of the Criteria to implement pagination in my frontend.
If you can write the statement in SQL then you can probably get away with the approach mentioned in this post which is to create a custom subclass of Order.
I think you can simply use the "." separator and write your code as follow
criteria.createAlias("thirdColumn", "t");
criteria.addOrder(Order.asc("t.field"));

Mongodb Java MapReduce getOutputCollection

I don't know anything about the OutputTypes. I'm trying something like this:
output=collection.mapReduce(map,reduce,null,
MapReduceCommand.OutputType.INLINE,null);
collection=output.getOutputCollection();
But the collection is null, because of the INLINE output type. I need the reduced collection because I need to reduce it further. How could I do this?
I found the solution to this finally
output=collection.mapReduce(map,reduce,"mymap",MapReduceCommand.OutputType. REDUCE,null);
collection=output.getOutputCollection();
note that you cannot store in same target "mymap" again and again. You have to use different name when you are looping like "mymap".concat(Integer.toString(i))

Categories

Resources