Elasticsearch multiple fields autosuggestion - java

I want to implement autosuggestion functionality using elastic search. I can use nGram filters to match partial words on multiple fields and its working fine as expected. Output of the search returns full document with multiple fields as required. Now my problem is, how do I give autosuggestion to the user based on the matching field. e.g. I have got 5 fields:
{userId:'rakesh',firstName:'Rakesh','lastName':'Goyal','mobileNo':'123-123-1234','alternativeMobileNo':'123-123-1235'}
{userId:'goyal',firstName:'Goyal','lastName':'Rakshit','mobileNo':'123-123-1236','alternativeMobileNo':'123-123-1237'}
In the above example if user types 123, I want to return 123-123-1234, 123-123-1235, 123-123-1236, 123-123-1237 (4 auto suggestions).
Similarly if user types Rak, I want to return Rakesh, Rakshit (2 auto suggestions).
How do I know match exists in mobileNo and alternativeMobileNo field for first example and return results accordingly?
How do I know match exists in firstName and lastName field for second example and return results accordingly?

How do I give autosuggestion to the user based on the matching field?
When user types 123, store it in a Java variable, prepare a query like below inserting that variable into and send a request to ElasticSearch.
{
"query" : {
"query_string" : {
"query" : "*123*"
}
}
}
The above query will manage to check it in both fields mobileNo and alternativeMobileNo.
Similarly, if user types Rak, the query will be similar to the previous one,
{
"query" : {
"query_string" : {
"query" : "*Rak*"
}
}
}
And I think you want to use highlighter api to answer your last how questions, which allows to highlight search results on one or more fields.
A screenshot of highlight example in es :

Related

How to search in firebase database

I'm trying to filter the data from my database using this code:
fdb.orderByChild("title").startAt(searchquery).endAt(searchquery+"\uf8ff").addValueEventListener(valuelistener2);
My database is like this:
"g12" : {
"Books" : {
"-Mi_He4vHXOuKHNL7yeU" : {
"title" : "Technical Sciences P1"
},
"-Mi_He50tUPTN9XDiVow" : {
"title" : "Life Sciences"
},
"-Mi_He51dhQfl3RAjysQ" : {
"title" : "Technical Sciences P2"
}}
While the code works, it only returns the first value that matches the query and doesn't fetch the rest of the data even though it matches.
If I put a "T" as my search query, I just get the first title "Technical Sciences P1 " and don't get the other one with P2
(Sorry for the vague and common question title, it's just I've been looking for a solution for so long)
While the codes works, it only returns the first value that matches the query
That's the expected behavior since Firebase Realtime Database does not support native indexing or search for text fields in database properties.
When you are using the following query:
fdb.orderByChild("title").startAt(searchquery).endAt(searchquery+"\uf8ff")
It means that you are trying to get all elements that start with searchquery. For example, if you have a title called "Don Quixote" and you search for "Don", your query will return the correct results. However, searching for "Quix" will yield no results.
You might consider downloading the entire node to search for fields client-side but this solution isn't practical at all. To enable full-text search of your Firebase Realtime Database data, I recommend you to use a third-party search service like Algolia or Elasticsearch.
If you consider at some point in time to try using Cloud Firestore, please see the following example:
Is it possible to use Algolia query in FirestoreRecyclerOptions?
To see how it works with Cloud Firestore but in the same way, you can use it with Firebase Realtime Database.

Connecting two DatabaseReferences in Android

I have a firebase realtime database, where for every user i have the ids of the groups, they are member of, stored. I have the names of the groups stored seperately. Now what I'm trying to do is to display the users groups ordered alphabetically by the group name (GroupA, GroupB, GroupH, GroupX, ...). But I can't really figure out, how to connect the two references. Does anyone know a way to do it? I don't think it is possible to filter children based on a list of valid keys in realtime database, there's only equalTo, startAt etc. Or do I have to just load the ids, get the corresponding group names, and order them myself?
Here's my database structure:
"group_profiles" : {
"-MAz5iuen-BpsLWP1TR0" : { //GID
"name" : "GroupA"
},
"-MAkiUQ7UnIttXy0ZgZx" : { //GID
"name" : "GroupB"
}
},
"groups" : {
"iwfcfGR4TNatxwxpqEAx7ycNfT43" : { //UID
"-MAz5iuen-BpsLWP1TR0" : { //GID
"key" : "..."
},
"-MAkiUQ7UnIttXy0ZgZx" : { //GID
"key" : "..."
}
},
...
Or do I have to just load the ids, get the corresponding group names, and order them myself?
That's one way to do it.
The other way is to duplicate the required data from the groups into groups_profiles for the purpose of performing the query. This is common in nosql type databases, and is called "denormalization".

Get only partially matching records in Solr

Is there a way to get records which matches a query partially in Solr.
For &q="java enterprise" in the below mentioned records,
{
"name":"java",
"case:"enterprise",
},
{
"name":"java enterprise"
"case": "enterprise"
}
I want to fetch only those records which have java and enterprise mentioned separately and not together, i.e only the below record should come into my result.
{
"name":"java",
"case:"enterprise",
}
Is there a way to search for only those records and eliminate the documents from the search which has exact match?
You don't need to use exact phrase match, instead, you can use boolean queries in that case
(name:"java" AND case:"enterprise" ) OR (name:"enterprise" AND case:"java" )

Spring mongo query collection on property with underscore char

I'm building a query to retrieve elements from a mongo collection, using MongoTemplate. The query criteria contains a property with an underscore, that somehow is replaced with '._', making the query always return 0 elements.
Criteria matchingCriteria = Criteria
.where("entries").elemMatch(Criteria.where("app_id").is(appId))
Looking to the logs I can see the generated query as follows:
o.s.data.mongodb.core.MongoTemplate: find using query: { "entries" : { "$elemMatch" : { "app._id" : "5834718ab0"}}} fields: null for class: Ranking in collection: ranking
I've already tried with BasicQuery, slashing underscore with '\\', and using the unicode “app\u005Fid". None of them worked. It's important to note that a collection with name "app" exists in my database.
The behaviour doesn't look standard. When I use another property with an underscore the value is not replaced:
Criteria matchingCriteria = Criteria .where("entries").elemMatch(Criteria.where("unique_app_id").‌​is(appId))
The logs:
o.s.data.mongodb.core.MongoTemplate find using query: { "entries" : { "$elemMatch" : { "unique_app_id" : "1131706359"}}} fields: null for class: class Ranking in collection: ranking
entries is an array with collection with the following format:
{
"instanceId" : "654ba2d16579e",
"app_id" : "583471adb0",
"unique_app_id" : "554577506",
"value" : 169
}
It's worth mentioning that the same query (without the underscore replacement) works fine in a mongo IDE (Robomongo in this case).
I'm using spring-boot-starter-data-mongodb 1.4.1.RELEASE.
I'm really out of ideas right now.
Any suggestion ?
Per section 3.4.3 of this Spring Data Commons documentation:
As we treat underscore as a reserved character we stongly advise to
follow standard Java naming conventions (i.e. not using underscores in
property names but camel case instead).
I don't believe you can use an underscore character in the middle of an element's name using Spring. Manual references are named after the referenced collection. Use the document type (collection name in singular) followed by _id ( <document>_id ). This is the only case where you can use underscore in the middle.
Update: Here is an existing pull request for the exact behavior you're seeing, as well as Spring's bug tracker for it.
From the Mongo shell, I can execute the following query with success:
> db.app.findOne({ "entries" : { "$elemMatch" : { "app_id" : "1"}}})
{
"_id" : ObjectId("58a5bc6afa8dd4ae3097d5f7"),
"name" : "Keith",
"entries" : [
{
"instanceId" : "654ba2d16579e",
"app_id" : "1"
}
]
}
So, perhaps the Spring API doesn't split when it finds multiple _ tokens when parsing a criteria, but does split for traversal when parsing one.

MongoDB full text search index: error: too many text index for, why?

I have one problem, I have collection and I want to set text search index to 2 fields(description and title). But when I add second index I get following error and text search stopped working.
{ "serverUsed" : "localhost/127.0.0.1:27017" , "ok" : 0.0 , "errmsg" : "too many text index for: testdb.users"}
when I delete one index search start work again. what is the problem? One collections support full text search index only for one field????
I am using the current version of mongodb under windows and I am using mongodb java driver API.
Thanks
MongoDB only allows one text-index per collection.
But you can use a text-index which spans multiple fields:
db.collection.ensureIndex( {
description: "text",
title: "text"
} );
That way you will get results when the phrase you are searching for is found in either. When this is not what you want, like when you have two search-queries which each return results from one of the fields but not the other, you have two options.
use a multi-field text index, but discard the results which come from the wrong field on the application layer.
extract one of the two fields to a different collection. The documents in that collection could either contain full copies, redacted copies or just the field you index and the _id of the original document.
To create a text based index on a key, use command db.collectionName.ensureIndex({'textColumnName': 'text'}). After this index is applied, use the search commands to search for a word i.e. db.collectionName.find({$text: {$search:'your text here'}}). There is a text score based on which the results are ranked, to see it project it in the score key like this : db.collectionName.find({$text: {$search:'your text here'}}, {score: {$meta: 'textScore'}}).sort({score: {$meta: 'textScore'}}).
If we create a text index on the title field of the movies collection, and then perform the text search db.movies.find( { $text : { $search : "Big Lebowski" } } ). The following documents will be returned, assuming they are in the movies collection:
{ "title" : "The Big Lebowski" , star: "Jeff Bridges" }
{ "title" : "Big" , star : "Tom Hanks" }
{ "title" : "Big Fish" , star: "Ewan McGregor" }
This is because, there will be a ***logical OR***ing on Big & Lebowski.

Categories

Resources