#NamedQuery cachable result alternative - performance

I'm using #NamedQuery to get some results from my DataBase. After manipulating it for a while, I understood that the #NamedQuery is requested once the application is deployed & stored it in the cache for more performance.
So, I'm searching for a way(kind of query) that get always the information from database when the request is made, so I can get always updated data ?
And if there is a way to do such a thing, what is its performance ?

As outlined already in the comments, you have misunderstanding of the NamedQuery. Not the result is stored in cache, but the query SQL is.
Nevertheless sometimes the EntityManager caches some things and I guess you need a solution for that....
If you are working with Query objects (e.g. EntityManager.createNamedQuery("nameOfYourQuery")) and EclipseLink then you can do the following:
Query query = EntityManager.createNamedQuery("nameOfYourQuery");
query.setHint(QueryHints.REFRESH, HintValues.TRUE);
query.getResultList();
You can also setup query hints directly in the NamedQuery like this:
#NamedQuery(name = "something", query = "SELECT n FROM something",
hints=#QueryHint(name=QueryHints.REFRESH, value=HintValues.TRUE))
Another way with query hints would be this one:
query.setHint(QueryHints.CACHE_USAGE, CacheUsage.DoNotCheckCache);
For a list of possible query hints, have a look at the EclipseLink docs.
If you want to completely deactivate database result caching you can also try the following in your persistence.xml:
<property name="eclipselink.query-results-cache" value="false"/>

Related

How to perform a Join query on Elastic Search via springboot/java?

I have a springboot application that interacts with elastic search (or as it know now OpenSearch). It can perform basic operations such as search, index etc. I used this as my base (although I replaced high level client since it is deprecated) and to perform queries, I am using #Query annotation mostly (as described in section 2.2 here, although I also used QueryBuilders).
Now, I have an interesting use case - I would like to perform 2 queries at the same time. First query would find a file in elastic search that would contain 3 ids. These 3 ids are ids of other files in the same elastic search. The 2nd query would look for these 3 files and finally return them to me. Now, I can easily do it in 2 steps:
Have a query to find a file containing 3 ids and return it
Have a second query (multisearch query can do bulk search as I understand) to search
for 3 files using info from the first query.
However, I need them to happen within the same query - so within the same query I need to search for a file containing the 3 ids and then perform a search for these 3 files.
So currently my files in elastic search look like so:
{
"docId": "docId57",
"relatedDocs": [
{
"relatedId": "docId1",
"type": "apple"
},
{
"relatedId": "docId2",
"type": "orange"
},
{
"relatedId": "docId3",
"type": "banana"
}
]
}
and my goal is to have a query that will accept docId57 as an arg (so a method findFilesViaJoin(docId57) or something) and return a list of 3 files: file for docId1, file docId2 and file for docId3.
I know it is possible either via nested queries, child/parent queries or good old SQL queries (via jpa/hibarnate).
I attempted to use all of these and was unsuccessful for reasons described below.
Child/parent queries
So for child/parent queries, I attempted to use DSL with #Query but couldn't quite get it since I don't have a solid documentation to refer to (the one that actually helps with java not curls). After some time I found this and this articles - I maybe can figure out how to make it work with child/parent but neither explain how to do mapping. If this approach can do what I want, my question is: how to set up & map parent/child in springboot.
Using SQL queries
So for this one, I need to change my set up to use hibarnate. I used this as my base. It works, the only problem I have is that my SQL queries get ignored. Instead, the search is done based of a method's name, not the content of #Query. So it is as if I don't have an annotation used at all. So using the structure mentioned above, the following method in my app:
#Query("select t from MyModel t where t.docId = ?1")
findByRelatedDocsRelatedId(String id)
will return files that has a relatedId that matches the id passed via method ard id (as oppose to reading query from #Query that tells method to search all docs based on docId). Now, I don't mind using method name as a query to search for something. But then why would I use #Query for? (not to mention how do I create a name that does join). It might be possible that my hibernate is set up wrong (never used it before this week). So question here is, does anybody have a nice complete example of hibarnate being used with elastic search that does join query?
Nested queries
For these queries, I assume that I just need to figure out what to put inside the #Query but due to limited documentation about how to compose nested query I didn't manage to make it even remotely to work. Any concreate documentation on how to create DSL nested query would be appreciated.
Any of the ways I described will work for me. I think child/parent seems the best choice (seeing as they kind created for this purpose) but any will do.

Can Spring Data Jpa Repository be used to create complex queries?

First of all some context: i have 2 entities CommodityData(commodityId, code, defaultDescription) and CommodityDescription(commodityId, lang, description). The defaultDescription field in first table use english and the localizated description is in second table.
Using pure JPA i get what i need but i would like to know if it is possible to implement it using SpringDataJpa Repository and Specifications (avoiding JPQL).
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<CommodityLang> query = cb.createQuery(CommodityLang.class);
Root<CommodityData> commodity = query.from(CommodityData.class);
Join<CommodityData, CommodityDescription> join = commodity.join("descriptions", JoinType.LEFT);
join.on(cb.equal(join.get("lang"), lang));
query.select(
cb.construct(CommodityLang.class,
commodity.get("categoryId"),
commodity.get("code"),
commodity.get("parent"),
commodity.get("path"),
commodity.get("defaultDescription"),
commodity.get("legacyLink"),
commodity.get("documentId"),
commodity.get("type"),
commodity.get("status"),
join.get("description"),
join.get("lang")
));
TypedQuery<CommodityLang> typedQuery = em.createQuery(query);
List<CommodityLang> results = typedQuery.getResultList();
The use of Spring Data Repository would be interesting because it would avoid handling pagination and sorting, but reading the source of SimpleJpaRepository I think it's not possible. It's correct?
Thank you,
Gabriele
PS: Left join use a on condition to do some filter on records.
You can combine repositories and specifications:
UserSpecification useSpecification =
new UserSpecification(new SearchCriteria("lastname", ":", "Trump"));
List<User> results = repository.findAll(useSpecification);
You also get paging, look at this example
After one year of development we have come to a compromise.
With JPA we have made even custom repositories very complex but we have found that over time they are not very maintainable and you cannot do a great optimization.
For CRUD operations we use SpringData over JPA, for complex report we use MyBatis that allows us to tune queries.
With a similar stack so i suggest to use this combo.

This filters in memory right?

I Just want to make sure I understand this correctly...
search is an object that contains a querystring.
Repo.Query returns an ObjectQuery<T>.
From my understanding the chained linq statements will filter the results after entity framework has returned all the rows satisfying the query. So really ALL the rows are being returned and THEN filtered in memory. So we are returning a bunch of data that we don't really want. There's about 10k rows being returned so this is kind of important. Just like to get my confusion cleared up.
var searchQuery = Repo.Query(search)
.Where(entity =>
entity.Prop1.ToUpper().Equals(prop1.ToUpper()) &&
entity.Prop2.ToUpper().Equals(prop2.ToUpper()))
.OrderBy(entity => Repo.SortExpression ?? entity.prop1);
Your Repo.Query(string query) function should return IQueryable<T>.
Then you can filter and order without getting all rows first.
IQueryable(Of T) Interface
hope this helps
If this is to SQL, this will most likely create a SQL query and filter on the server and not in memory.
As a matter of fact, the statement above wouldn't actually do anything.
It's only when you iterate over it that the query will be executed. This is why certain providers (like the EF to SQL one) can collapse expression trees into a SQL query.
Easiest way to check is to use LINQPAD or the SQL Profiler to see what query is actually is executed.

Linq Query instead of Contains Operator for Performance issue

I have to Pull all customers whose ids are in the list
I have a list of CustomerID`s
List custidlist=new List{1,2,3....etc.}();
i have to write a linq query to get all customers whose id`s are in the above list
custidlist.
var customers=db.Customers.Where(c=> custidlist.Contains(c.customerid));
Using Contains is not good in performance issue.
Can we use COMPARE OPERATOR LIKE THIS
var customers=db.Customers.Where(c=> custidlist.Compare(c.customerid)); ????
I Heard Compare is best for Performance
Since this is Linq to SQL / Entities your Linq Contains query will be translated to a SQL statement roughly like:
select * from Customers where customerId in (1,2,3)
Not only is your other suggestion not supported, but also you cannot do any better than this SQL performance wise.
When you write a Contains query in Linq to SQL it iwll be fired as an in query in SQL and running your query on the databse should be the fastest..
one caveats to this though is to remember in query might have a limit on the number of entities I think its around 2000+ in sql server and the way around this would be to batch your query.

NHibernate 3.0 Linq query against <map> element instead of using HQL

I have a mapping that looks like this:
<class name="Record">
<map name="Values">
<key column="RecordFK"/>
<index column="FieldFK"/>
<element column="Value"/>
</map>
</class>
Translating this to English: a Record maps Fields to Values. In HQL, I can query this map, as follows:
from Record rec where rec.Values[:fieldFK] = :value
Is it possible to recreate this query using the new Linq provider in NHibernate 3.0 instead of HQL? I tried the following code without success:
var records = session.Query<Record>()
.Where(rec => rec.Values[field.Key] == "foo");
This produced an error when NHibernate tried to interpret the dictionary accessor:
System.NotSupportedException:
System.String get_Item(System.Int32)
Is there some way to "teach" NHibernate how to turn this C# expression into SQL?
NHibernate 3 does have a way to extend the provider to allow more expressions, check http://fabiomaulo.blogspot.com/2010/07/nhibernate-linq-provider-extension.html
However, this looks like something that should be supported. My suggestion is that you create a ticket at http://jira.nhforge.org with a failing test case.
If you're feeling like doing a little bit more, you can dive into https://nhibernate.svn.sourceforge.net/svnroot/nhibernate/trunk/nhibernate/src/NHibernate/Linq and create a patch. That will make things faster.
Update (2010-12-04): My patch has been merged into the trunk. This scenario is now supported (you can compile from source, or wait a few days for the final release)
NHibernate makes queries pretty simple with CreateCriteria as well. Heres an example:
var records = session.CreateCriteria<Record>()
.Add(Restrictions.Eq("Key", "foo)
.List<Record>();
But NHibernate does have a Linq provider that works as well. I'm not sure what Values[field.Key] but thats probably whats throwing the error. Ideally you should be selecting a "Column" to compare against "foo".

Resources