Ebean query for string that start with then contains a specific string
up vote
1
down vote
favorite
I got a little issue here with a query for a string to search in DB for auto-complete functionality, the problem that I got that I need first results to be all statements that "Start" with then the statements that contain that string!
For example: If I got the following records in a table in the database:
- Awesome service to provide
- Something else here
- Extra Service
- My Service is awesome
- Service Provided
- Zoo Services
And I started to type "Service" I need No. 5 to show first, then the rest of items ( 1, 3, 4, 6)
I know how to do that in MySQL, something like:
select * from `services` where `name` like '%Service%' order by `name` like 'Service%' desc;
Or maybe like the ways mentioned here: MySQL order by "best match"
but I need to do that in Ebean.
I tried:
return Service.find.query().where().icontains("name", search).findList()
But this return with 1, 3, 4, 5, 6,
and now I do the following:
final List<Service> list = Service.find.query().where()
.istartsWith("name", search)
.orderBy("name").findList(); // First query
list.addAll(Service.find.query().where()
.icontains("name", search)
.not().istartsWith("name", search)
.orderBy("name").findList()); // Then add the results for the second query
return list;
This will do the job, 5, 1, 3, 4, 6 but I don't like it, because I hit database with 2 queries, also I do exclude the first query in complex data type query in the second query, but anyway, is it a correct way? if not, do you have a suggestion or solution for a better way?
Table:
CREATE TABLE `services` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE services ADD UNIQUE `uq_services_name`(name);
EBean entity
Service.java:
@Entity
@Table(name = "services")
public class Service extends BaseModel<Service> {
public static Finder<Integer, Service> find = new Finder<>(Service.class);
@Column(nullable = false, unique = true)
private String name;
// ... setters and getters
}
BaseModel.java:
@MappedSuperclass
public abstract class BaseModel<T> extends Model {
@Id
@Column
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
public final Integer getId() {
return id;
}
@SuppressWarnings("unchecked")
public final T setId(Integer id) {
this.id = id;
return (T) this;
}
}
java playframework ebean
add a comment |
up vote
1
down vote
favorite
I got a little issue here with a query for a string to search in DB for auto-complete functionality, the problem that I got that I need first results to be all statements that "Start" with then the statements that contain that string!
For example: If I got the following records in a table in the database:
- Awesome service to provide
- Something else here
- Extra Service
- My Service is awesome
- Service Provided
- Zoo Services
And I started to type "Service" I need No. 5 to show first, then the rest of items ( 1, 3, 4, 6)
I know how to do that in MySQL, something like:
select * from `services` where `name` like '%Service%' order by `name` like 'Service%' desc;
Or maybe like the ways mentioned here: MySQL order by "best match"
but I need to do that in Ebean.
I tried:
return Service.find.query().where().icontains("name", search).findList()
But this return with 1, 3, 4, 5, 6,
and now I do the following:
final List<Service> list = Service.find.query().where()
.istartsWith("name", search)
.orderBy("name").findList(); // First query
list.addAll(Service.find.query().where()
.icontains("name", search)
.not().istartsWith("name", search)
.orderBy("name").findList()); // Then add the results for the second query
return list;
This will do the job, 5, 1, 3, 4, 6 but I don't like it, because I hit database with 2 queries, also I do exclude the first query in complex data type query in the second query, but anyway, is it a correct way? if not, do you have a suggestion or solution for a better way?
Table:
CREATE TABLE `services` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE services ADD UNIQUE `uq_services_name`(name);
EBean entity
Service.java:
@Entity
@Table(name = "services")
public class Service extends BaseModel<Service> {
public static Finder<Integer, Service> find = new Finder<>(Service.class);
@Column(nullable = false, unique = true)
private String name;
// ... setters and getters
}
BaseModel.java:
@MappedSuperclass
public abstract class BaseModel<T> extends Model {
@Id
@Column
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
public final Integer getId() {
return id;
}
@SuppressWarnings("unchecked")
public final T setId(Integer id) {
this.id = id;
return (T) this;
}
}
java playframework ebean
add a comment |
up vote
1
down vote
favorite
up vote
1
down vote
favorite
I got a little issue here with a query for a string to search in DB for auto-complete functionality, the problem that I got that I need first results to be all statements that "Start" with then the statements that contain that string!
For example: If I got the following records in a table in the database:
- Awesome service to provide
- Something else here
- Extra Service
- My Service is awesome
- Service Provided
- Zoo Services
And I started to type "Service" I need No. 5 to show first, then the rest of items ( 1, 3, 4, 6)
I know how to do that in MySQL, something like:
select * from `services` where `name` like '%Service%' order by `name` like 'Service%' desc;
Or maybe like the ways mentioned here: MySQL order by "best match"
but I need to do that in Ebean.
I tried:
return Service.find.query().where().icontains("name", search).findList()
But this return with 1, 3, 4, 5, 6,
and now I do the following:
final List<Service> list = Service.find.query().where()
.istartsWith("name", search)
.orderBy("name").findList(); // First query
list.addAll(Service.find.query().where()
.icontains("name", search)
.not().istartsWith("name", search)
.orderBy("name").findList()); // Then add the results for the second query
return list;
This will do the job, 5, 1, 3, 4, 6 but I don't like it, because I hit database with 2 queries, also I do exclude the first query in complex data type query in the second query, but anyway, is it a correct way? if not, do you have a suggestion or solution for a better way?
Table:
CREATE TABLE `services` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE services ADD UNIQUE `uq_services_name`(name);
EBean entity
Service.java:
@Entity
@Table(name = "services")
public class Service extends BaseModel<Service> {
public static Finder<Integer, Service> find = new Finder<>(Service.class);
@Column(nullable = false, unique = true)
private String name;
// ... setters and getters
}
BaseModel.java:
@MappedSuperclass
public abstract class BaseModel<T> extends Model {
@Id
@Column
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
public final Integer getId() {
return id;
}
@SuppressWarnings("unchecked")
public final T setId(Integer id) {
this.id = id;
return (T) this;
}
}
java playframework ebean
I got a little issue here with a query for a string to search in DB for auto-complete functionality, the problem that I got that I need first results to be all statements that "Start" with then the statements that contain that string!
For example: If I got the following records in a table in the database:
- Awesome service to provide
- Something else here
- Extra Service
- My Service is awesome
- Service Provided
- Zoo Services
And I started to type "Service" I need No. 5 to show first, then the rest of items ( 1, 3, 4, 6)
I know how to do that in MySQL, something like:
select * from `services` where `name` like '%Service%' order by `name` like 'Service%' desc;
Or maybe like the ways mentioned here: MySQL order by "best match"
but I need to do that in Ebean.
I tried:
return Service.find.query().where().icontains("name", search).findList()
But this return with 1, 3, 4, 5, 6,
and now I do the following:
final List<Service> list = Service.find.query().where()
.istartsWith("name", search)
.orderBy("name").findList(); // First query
list.addAll(Service.find.query().where()
.icontains("name", search)
.not().istartsWith("name", search)
.orderBy("name").findList()); // Then add the results for the second query
return list;
This will do the job, 5, 1, 3, 4, 6 but I don't like it, because I hit database with 2 queries, also I do exclude the first query in complex data type query in the second query, but anyway, is it a correct way? if not, do you have a suggestion or solution for a better way?
Table:
CREATE TABLE `services` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE services ADD UNIQUE `uq_services_name`(name);
EBean entity
Service.java:
@Entity
@Table(name = "services")
public class Service extends BaseModel<Service> {
public static Finder<Integer, Service> find = new Finder<>(Service.class);
@Column(nullable = false, unique = true)
private String name;
// ... setters and getters
}
BaseModel.java:
@MappedSuperclass
public abstract class BaseModel<T> extends Model {
@Id
@Column
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
public final Integer getId() {
return id;
}
@SuppressWarnings("unchecked")
public final T setId(Integer id) {
this.id = id;
return (T) this;
}
}
java playframework ebean
java playframework ebean
edited Nov 19 at 9:22
asked Nov 18 at 10:09
Al-Mothafar
3,98634474
3,98634474
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
up vote
0
down vote
Mothafar.
That's a good question. I guess you don't like your solution because it queries the database twice. So what about querying first and then sorting afterwards:
final List<Service> list = Service.find.query().where()
.icontains("name", search)
.findList()
.sort(Comparator.comparingInt(service -> service.getName().indexOf(search)))
);
return list;
This way #5 comes first and then the rest ordered by the appearance index of the search term. The caveat is that the sorting is not done through the database. But maybe it is possible to integrate such condition into the orderBy-clause.
Cheers
Jens
Thanks, but the problem with this that it will be really painful for a processor to handle this search over and over of each record, it is about 20K records, so it sounds like 2 queries ending with better performance than this, I think, am I right?
– Al-Mothafar
Nov 18 at 22:12
Alright. However, the sorting will be applied to the result set only. Will this have 20k records as well?
– Jens.Huehn_at_SlideFab.com
Nov 18 at 22:28
In the worst case, yes, in most cases, easier to hit around 10Ks, it is auto-complete so you can imagine how frequent will get hittings.
– Al-Mothafar
Nov 18 at 22:34
true, so for auto-complete maybe some kind of throttling makes sense: AJAX requests only every second instead of after every letter. Minimum length of 2 or maybe 3 letters and such things can help. This shouldn't hurt UX too much.
– Jens.Huehn_at_SlideFab.com
Nov 19 at 6:57
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
0
down vote
Mothafar.
That's a good question. I guess you don't like your solution because it queries the database twice. So what about querying first and then sorting afterwards:
final List<Service> list = Service.find.query().where()
.icontains("name", search)
.findList()
.sort(Comparator.comparingInt(service -> service.getName().indexOf(search)))
);
return list;
This way #5 comes first and then the rest ordered by the appearance index of the search term. The caveat is that the sorting is not done through the database. But maybe it is possible to integrate such condition into the orderBy-clause.
Cheers
Jens
Thanks, but the problem with this that it will be really painful for a processor to handle this search over and over of each record, it is about 20K records, so it sounds like 2 queries ending with better performance than this, I think, am I right?
– Al-Mothafar
Nov 18 at 22:12
Alright. However, the sorting will be applied to the result set only. Will this have 20k records as well?
– Jens.Huehn_at_SlideFab.com
Nov 18 at 22:28
In the worst case, yes, in most cases, easier to hit around 10Ks, it is auto-complete so you can imagine how frequent will get hittings.
– Al-Mothafar
Nov 18 at 22:34
true, so for auto-complete maybe some kind of throttling makes sense: AJAX requests only every second instead of after every letter. Minimum length of 2 or maybe 3 letters and such things can help. This shouldn't hurt UX too much.
– Jens.Huehn_at_SlideFab.com
Nov 19 at 6:57
add a comment |
up vote
0
down vote
Mothafar.
That's a good question. I guess you don't like your solution because it queries the database twice. So what about querying first and then sorting afterwards:
final List<Service> list = Service.find.query().where()
.icontains("name", search)
.findList()
.sort(Comparator.comparingInt(service -> service.getName().indexOf(search)))
);
return list;
This way #5 comes first and then the rest ordered by the appearance index of the search term. The caveat is that the sorting is not done through the database. But maybe it is possible to integrate such condition into the orderBy-clause.
Cheers
Jens
Thanks, but the problem with this that it will be really painful for a processor to handle this search over and over of each record, it is about 20K records, so it sounds like 2 queries ending with better performance than this, I think, am I right?
– Al-Mothafar
Nov 18 at 22:12
Alright. However, the sorting will be applied to the result set only. Will this have 20k records as well?
– Jens.Huehn_at_SlideFab.com
Nov 18 at 22:28
In the worst case, yes, in most cases, easier to hit around 10Ks, it is auto-complete so you can imagine how frequent will get hittings.
– Al-Mothafar
Nov 18 at 22:34
true, so for auto-complete maybe some kind of throttling makes sense: AJAX requests only every second instead of after every letter. Minimum length of 2 or maybe 3 letters and such things can help. This shouldn't hurt UX too much.
– Jens.Huehn_at_SlideFab.com
Nov 19 at 6:57
add a comment |
up vote
0
down vote
up vote
0
down vote
Mothafar.
That's a good question. I guess you don't like your solution because it queries the database twice. So what about querying first and then sorting afterwards:
final List<Service> list = Service.find.query().where()
.icontains("name", search)
.findList()
.sort(Comparator.comparingInt(service -> service.getName().indexOf(search)))
);
return list;
This way #5 comes first and then the rest ordered by the appearance index of the search term. The caveat is that the sorting is not done through the database. But maybe it is possible to integrate such condition into the orderBy-clause.
Cheers
Jens
Mothafar.
That's a good question. I guess you don't like your solution because it queries the database twice. So what about querying first and then sorting afterwards:
final List<Service> list = Service.find.query().where()
.icontains("name", search)
.findList()
.sort(Comparator.comparingInt(service -> service.getName().indexOf(search)))
);
return list;
This way #5 comes first and then the rest ordered by the appearance index of the search term. The caveat is that the sorting is not done through the database. But maybe it is possible to integrate such condition into the orderBy-clause.
Cheers
Jens
answered Nov 18 at 21:18
Jens.Huehn_at_SlideFab.com
1225
1225
Thanks, but the problem with this that it will be really painful for a processor to handle this search over and over of each record, it is about 20K records, so it sounds like 2 queries ending with better performance than this, I think, am I right?
– Al-Mothafar
Nov 18 at 22:12
Alright. However, the sorting will be applied to the result set only. Will this have 20k records as well?
– Jens.Huehn_at_SlideFab.com
Nov 18 at 22:28
In the worst case, yes, in most cases, easier to hit around 10Ks, it is auto-complete so you can imagine how frequent will get hittings.
– Al-Mothafar
Nov 18 at 22:34
true, so for auto-complete maybe some kind of throttling makes sense: AJAX requests only every second instead of after every letter. Minimum length of 2 or maybe 3 letters and such things can help. This shouldn't hurt UX too much.
– Jens.Huehn_at_SlideFab.com
Nov 19 at 6:57
add a comment |
Thanks, but the problem with this that it will be really painful for a processor to handle this search over and over of each record, it is about 20K records, so it sounds like 2 queries ending with better performance than this, I think, am I right?
– Al-Mothafar
Nov 18 at 22:12
Alright. However, the sorting will be applied to the result set only. Will this have 20k records as well?
– Jens.Huehn_at_SlideFab.com
Nov 18 at 22:28
In the worst case, yes, in most cases, easier to hit around 10Ks, it is auto-complete so you can imagine how frequent will get hittings.
– Al-Mothafar
Nov 18 at 22:34
true, so for auto-complete maybe some kind of throttling makes sense: AJAX requests only every second instead of after every letter. Minimum length of 2 or maybe 3 letters and such things can help. This shouldn't hurt UX too much.
– Jens.Huehn_at_SlideFab.com
Nov 19 at 6:57
Thanks, but the problem with this that it will be really painful for a processor to handle this search over and over of each record, it is about 20K records, so it sounds like 2 queries ending with better performance than this, I think, am I right?
– Al-Mothafar
Nov 18 at 22:12
Thanks, but the problem with this that it will be really painful for a processor to handle this search over and over of each record, it is about 20K records, so it sounds like 2 queries ending with better performance than this, I think, am I right?
– Al-Mothafar
Nov 18 at 22:12
Alright. However, the sorting will be applied to the result set only. Will this have 20k records as well?
– Jens.Huehn_at_SlideFab.com
Nov 18 at 22:28
Alright. However, the sorting will be applied to the result set only. Will this have 20k records as well?
– Jens.Huehn_at_SlideFab.com
Nov 18 at 22:28
In the worst case, yes, in most cases, easier to hit around 10Ks, it is auto-complete so you can imagine how frequent will get hittings.
– Al-Mothafar
Nov 18 at 22:34
In the worst case, yes, in most cases, easier to hit around 10Ks, it is auto-complete so you can imagine how frequent will get hittings.
– Al-Mothafar
Nov 18 at 22:34
true, so for auto-complete maybe some kind of throttling makes sense: AJAX requests only every second instead of after every letter. Minimum length of 2 or maybe 3 letters and such things can help. This shouldn't hurt UX too much.
– Jens.Huehn_at_SlideFab.com
Nov 19 at 6:57
true, so for auto-complete maybe some kind of throttling makes sense: AJAX requests only every second instead of after every letter. Minimum length of 2 or maybe 3 letters and such things can help. This shouldn't hurt UX too much.
– Jens.Huehn_at_SlideFab.com
Nov 19 at 6:57
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53359737%2febean-query-for-string-that-start-with-then-contains-a-specific-string%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown