Lucene Search Sorting - grails

I need to search member's by first name and last name, which I have done successfully.
Next thing which I have to do is that member's connection should come first in the list (sorting by connection.), like in Facebook, friends come first in the list and than other users of the community.
I am using grails plugin Searchable. One simple way to do this is to sort the searchListFromSearchable w.r.t. connection's list.
Following is the domain structure.
class Member extends {
String firstName
String lastName
static searchable = {
analyzer "simple"
only = ['firstName', 'lastName']
firstName boost: 5.0
}
static hasMany = [connections: Connection]
}
And Connection class is as follow
class Connection {
String uuid
Member connectedMember
static belongsTo = [member: Member]
}
Is there any lucene way to do this ?

I think you can add the sort process in the collect step or score step in Lucene. I think you get the relationship first, and when search the member, you can check whether the member is in the relationship or not. If the member is in the relationship, you can add score of this doc, such as write your own collector which extend TopFieldDocCollector and add score *= 10f before super.collect() in the collect method .

On of the solution to add friends ids to index. In this case, your search query should have followed form +name:firstName +name:lastName friend:userId^10. The friendId has a bigger boost and will cause friends to a high rank in your query.

Related

how to get the relationship from Collection of relationships between two nodes using springdata Neo4j with GraphRepository

I have two entities like Users and Accounts. User node related to Account node
with any of the 20 relationships. Please find the sample image design attached
i need to search accounts for corresponding users using any of the 20 relationships. i used the cypher query for retriving user details and the accounts.. Relationship between the two entity will be either any one of the 20 relationships . so i can't annotate the #RelationshipEntity type value. Please find the code for example
User.java
public class User
{
private Long id;
String fulltextsearch;
String user_id;
String status;
#Relationship(type = "perm")
List<Acronym> acronym;
.....
...
}
Acronym.java
#JsonIdentityInfo(generator=JSOGGenerator.class)
#RelationshipEntity
public class Acronym {
#GraphId
Long id;
String acronym;
#StartNode
private User user;
#EndNode
private Account account;
....
....
}
Userrepository.java
#RepositoryRestResource(collectionResourceRel = "User", path = "User")
public interface Userrepository extends GraphRepository<User> {
User findByLogin(#Param("login") String login);
#Query("MATCH p=(user:User)-[r*0..1]->(account) WHERE user.login =~('(?i).*'+{Login}+'.*') RETURN p")
Collection<User> findByloginContaining(#Param("login") String login);
}
i tried creating objects for each relationship (ie 20 relationship object.). i'm not sure if that correct way to get the value.
Could anyone please help me to know to fetch the relationships against the account? it always retrives as null.
Thanks in advance.
The OGM/SDN 4 does not support unknown relationship types. The type of relationship must be specified on a #RelationshipEntity.
One way of doing this is as you said, create a #RelationshipEntity per type, but this also means that you must specify 20 such relationships in your User class, because the relationship type differs (even though the start/end nodes are the same). This may not be ideal, and difficult to manage.
If your application primarily works with dynamic relationship types, the OGM may not be a good fit.
NOTE: Mapping custom query results to entities is only supported in OGM 2.x / SDN 4.1. You cannot return a path, just the entities that make up the path such as nodes and rels.

How to make a "deep" transformation in Grails withCriteria contains projection?

I am using Grails 2.2.4 to build a web application, and now I am having a complex problem with Grails withCriteria operation. I have 3 classes as below:
class Person {
int id
String name
Set<Car> cars = [] // One-to-many relationship
Company currentCompany // One-to-one relationship
}
class Car {
int id
String manufacturer
String brand
double price
Person owner
}
class Company {
int id
String name
Set<Person> employees = []
}
And now I want to query data from Person as root class along with associated data like this:
List result = Person.withCriteria {
projections {
property('id')
property('name')
createAlias('cars', 'c', CriteriaSpecification.LEFT_JOIN)
property('c.brand')
createAlias('currentCompany', 'com', CriteriaSpecification.LEFT_JOIN)
property('com.name')
}
lt('id', 10L)
resultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY)
}
And the problem is, I don't know how to transform deeply the result data to a List of persons to make sure every single element contains its data as the class structure. I tried many methods like
resultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY)
resultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP)
resultTransformer(CriteriaSpecification.aliasToBean(Person.class))
but nothing worked as I expected.
Does Grails 2.2.4 support this? If yes so what is the correct syntax?
Thank you so much.
Actually, after researching many articles, Grails documentation and even its source code, I think the best way to do this is implementing a custom transformer for my own purpose. The most difficult thing here is how to transform data to association objects and gather them to collection inside the root entity. And I have created one here:
http://www.mycodestock.com/code/10333/
Hope it helps you guys who may need something like mine.

grails searchable plugin query

My Grails app is using the searchable plugin, which builds on Compass and Lucene to provide search functionality. I have two searchable classes, say Author and Book. I have mapped these classes to the search index, so that only certain fields can be searched.
To perform a search across both classes I simply call
def results = searchableService.search(query)
One of the nice features of doing the search across both class simultaneously, is that the results object includes metadata about number of results included, number of results available, pagination details etc.
I recently added a boolean approved flag to the Book class and I never want unapproved books to appear in the search results. One option is to replace the call above with:
def bookResults = Book.search(query + " approved:1")
def authorResults = Author.search(query)
However, I now need to figure out how to combine the metadata for both results, which is likely to be tricky (particularly pagination).
Is there a way to search across Book and Author with a single query, but only return approved books?
Do you want to be able to find authors or do you want to find books with a given author?
If you want to find books with a given author, you can configure your domain classes in the following way:
class Author {
String name
...
static searchable = {
root false
}
}
this will result in excluding the Author from the searchableService.search(query)-result and you'll find field names like $/Book/Author/name in your index. (use luke to examine your index: http://code.google.com/p/luke/).
You can change the name of those fields by configuring a better prefix in your Book-class:
class Book {
String name
Author author
...
static searchable = {
author component: [prefix: 'author']
}
}
this will change the name of the field in the index to bookauthor.
If you now search with searchableService.search(query), you'll find all books where the name of the book or the name of the author contains the search term. You can even restrict the search to a given author by using the authorname:xyz syntax.
If you really would like to mix the search results, I only know the solution you already mentioned: mixing both results with your own code, but I guess it will be hard to mix the scoring of the hits in a good way.
Update to your response: Here's my pagination code...
.gsp:
<div class="pagination">
<g:paginate total="${resultsTotal}" params="[q: params.q]"/>
</div>
controller:
result = searchableService.search(params.q, params)
[
resultList: result.results,
resultsTotal: result.total
]
So if you just merge the results of your two searches and add the result.totals, this could work for you.
I've created a test app and came to the following solution. maybe it helps...
if the property approved only has the states 0 and 1, the following query will work:
def results = searchableService.search(
"(${query} AND approved:1) OR (${query} -approved:0 -approved:1)"
)
I guess this can be reformulated in a better way if you don't use the QueryParser but the BooleanQueryBuilder.
BTW: if you add a method like
String getType() { "Book" }
and
String getType() { "Author" }
To your domains, you can even configure your search to do it like this
def results = searchableService.search(
"(${query} AND approved:1) OR (${query} AND type:Author)"
)

Grails createCriteria many-to-many

Imagine i have the following (this is a search mechanism for my website)
class Supermarket {
String sp_name
String sp_street
}
class Products {
String p_name
String p_price
}
class products_supermarket{
Supermarket sp
Products pro
}
Now i want to create a criteria:
def c = Supermarket.createCriteria()
def results = c.list {
like("sp_street", params.street)
and {
************ ... params.product
}
maxResults(10)
}
Where i have the * i want to be able to find products whithin that supermaked searching on products_supermarket class. How to do that?
PS. If criteria works as an each() method, iterating over all supermarkets, i could use an if-else statment to search for products, and if found i could use: idEq(it), where it is the supermarket id. This way i would make it. My problem is, i dont know how to get current'sm supermarket id. Any help?
and is applied to criterias inside it, so there's no point applying it to a single statement. Top-level criterias are and-ed by defauilt.
You usually better go without connector class, just by using hasMany: Supermarket and hasMany: Product in domain classes. Connector table will be auto-generated by Hibernate.
If you stick with ProductsSupermarket connector class, do add belongsTo: Supermarket and belongsTo: Product to it class, and add 'hasMany: ProductsSupermarket' to other two, or you're losing Grails' GORM advantage.
There's a section "Querying Associations" in the doc.
Object's id is as simple as that: mySupermarket.id, or mySupermarket.ident() if key field is named differently. id field is auto-added to class and table by default.
So the query is:
List<Supermarket> results = Supermarket.withCriteria {
like("sp_street", params.street)
productSupermarket {
product {
idEq(params.product)
}
// or just eq('product', someProduct)
}
************ ... params.product
maxResults(10)
}

Sorting query results according to parent property in grails

Is it possible in grails to sort query results according to a property of a parent class in a relationship. E.g. I have a user domain class which has a one to many relationship with a list of Tasks.
When showing the list page of the Tasks domain class, I want to be able to sort the list of tasks by the associated User name.
class User {
String name
String login
String group
List tasks = new ArrayList()
static hasMany = [tasks:Task]
}
class Task {
String summary
String details
User user
static belongsTo = [user:User]
}
I can do something like this
Task.list([sort:"user", order:"asc"])
But this sorts by the user.id, is there a way to specify the sort to be on the user.name?
You can do it using Criteria
def criteria = Task.createCriteria()
def taskList = criteria.list {
createAlias("user","_user")
order( "_user.name")
}
iirc, grails sorts by using toString() and since you have not supplied one, it uses the id.

Resources