Full Text Search in CouchDB - java

I am developing an web application on GWT Framework (JAVA). I am using CouchDB(NoSQL Database)
for storing user profile, user question and answers. I am new in NoSQL Database so i need to implement full text search in my application.
Example : " What is Java ?"
Desired Result : It could be found all the question which have all three words What, is, Java .
So there is any idea how to achieve this result in couchdb.

Use couchdb lucene The integration with couchdb is straightforward and it would be perfect for your use case. Couch-db lucene supports the entire query syntanx of lucene. For your problem the + could be used.
The "+" or required operator requires that the term after the "+" symbol exist somewhere in a the field of a single document.
Here is a sample query
http://localhost:5984/_fti/local/database/_design/design_name/index_name?q=+"What is java"

You can implement it using CouchDB List Functions.
I have a document where I need to search for keywords in name and description field. So, I created a view which will emit doc id as key and doc.name,doc._id,doc.description as value.
Now I created a List function which will use Javascript match function and give me the matching list of doc ids.
Sample Query:
http://localhost:5984/dashboard/_design/testSearch/_list/results/ByName?searchQuery=What is Java
{
"_id": "_design/testSearch",
"lists": {
"results": "function(head, req) { var query= new RegExp(req.query.searchQuery,'i'); var arr=new Array(); var key; var row; while(row = getRow()) { if(row.value[0].match(query) || row.value[2].match(query)) { arr.push([row.value[0].toUpperCase(),row.value[1]]); key = row.key;}} arr.sort(); send('{\"'+key+'\":\"'+arr+'\"}');}"
},
"views": {
"ByName": {
"map": "function (doc) {\n if((doc.isdeleted==\"false\" || doc.isdeleted==false) && doc.userid && doc.name){\n emit(doc._id,[doc.name,doc._id,doc.description]);\n }\n}"
}
},
"language": "javascript"
}

Related

Reindex selected _source fields using Rest high level client in java

I want to re_index only selected fields from my document in elasticsearch using Rest High level client.
I know the elasticsearch query to achieve that but I don't know it's equivalent query using rest client.
Following is the elasticsearch query which I am trying to implement using rest client -
{
"body" : {
"source" : {
"index" : "my source index name",
"_source" : "id, name, rollNo"
},
"dest" : {
"index" : "my destination index name"
}
}
}
To write its equivalent query using rest client in java, I have used the following code -
ReindexRequest reindexRequest = new ReindexRequest();
reindexRequest.setSourceIndices("source index name").setDestIndex("destination index name");
reindexRequest.setDocTypes("id", "name", "rollNo", "_doc");
client.reindex(reindexRequest,RequestOptions.DEFAULT);
But the above code is not working as expected. It's re_indexing all the fields of my document. I want only selective 3 fields to be re_indexed from each doc.
You need to use below code as setDocTypes is not used for source filtering.
As there is no direct method available for setting source filter so you need to change underlying search request suing below code.
ReindexRequest reindexRequest = new ReindexRequest();
reindexRequest.setSourceIndices("source index name").setDestIndex("destination index name");
reindexRequest.setDocTypes("_doc");
String[] include=new String[] {"id", "name", "rollNo"};
String[] exclude=new String[] {"test"};
reindexRequest.getSearchRequest().source().fetchSource(include, exclude);
client.reindex(reindexRequest,RequestOptions.DEFAULT);

Query to search value in side array of object

I want to apply criteria inside object of array if it matches, but I am not able to find any documentation or example where I can find that using spring-data-cosmosdb library. I am using 2.3.0 version of library.
Example of Json
{
"id" : 1,
"address" : [
{
"street" : "abc"
...
},
{
"street" : "efg"
...
}
]
}
I wan to search all documents in which address is having street name equals "abc". Below is spring boot code that I am using to search in cosmosDb. But it is not returning expected results.
List<Criteria> criteriaList = new ArrayList<>();
criteriaList.add(Criteria.getInstance(CriteriaType.IN, "addresses.street", Collections.singletonList("abc")));
List<User> users = cosmosTemplate.find(new DocumentQuery(criteriaList.get(0), CriteriaType.AND)), User.class, COLLECTION_NAME);
I also tried with address[0].street, but it is throwing exception of operation not supported.
Strongly recommend upgrading to spring-data-cosmosdb v3 (at least version 3.22.0). The v2 connector has been legacy for some time. Using the latest connector, the below would accomplish your goal.
Criteria filterCriteria = Criteria.getInstance(CriteriaType.ARRAY_CONTAINS, "address",
Collections.singletonList(new ObjectMapper().readTree("{\"street\":\"abc\"}")),
Part.IgnoreCaseType.NEVER);
CosmosQuery cosmosQuery = new CosmosQuery(filterCriteria);
Iterable<User> results = cosmosTemplate.find(cosmosQuery, User.class, COLLECTION_NAME);
for (User user : results)
System.out.println("doc id: " + user.getId());

Cloudant With Lucene Search Fails To Sort As Expected

I am pretty new to Cloudant but have developed in SQL on DB2 for some time. I am running into an issue where I *think I am using the Lucene query engine and Cloudant indexes to return results from my query. The query gets all the results I want however, they are not sorted correctly. I am wanting to sort the results alphabetically based on the "officialName" field. Because we are only returning the first 21 out of n results (and then we have a js handler to call more results via paging) we cannot sort in the java side but must do so via Cloudant. Our application is running Java and executed using IBM's Bluemix and WebSphere Liberty Profile. I have packaged the cloudant-client-2.8.0.jar and cloudant-HTTP-2.8.0.jar files to access the Cloudant database. We have many queries that are working so the connection itself is fine.
Here is the code that builds the Cloudant Client search object:
Search search = getCloudantDbForOurApp().search("bySearchPP-ddoc/bySearchPP-indx").includeDocs(true);
SearchResult<DeliverableDetails> result = search.sort(getSortJsonString(searchString)).querySearchResult(getSearchQuery(searchString), DeliverableDetails.class);
Here is the method getSortJsonString. It should be noted that the search string is typically NOT null. I should also note that leaving in or taking out the -score attribute does effect the search but never achieves alpha sorted results.
private String getSortJsonString(String searchString) {
String sortJson;
if (searchString != null && !searchString.isEmpty()) {
sortJson = "[\"-<score>\",\"officialName<string>\"]";
} else {
sortJson = "\"officialName<string>\"";
}
return sortJson;
}
Here is the getSearchQuery method's relevant code for reference:
...
query += "(";
query += "officialName:" + searchString + "^3";
query += " OR " + "deliverableName:" + searchString + "^3";
query += " OR " + "alias:" + searchString + "^3";
query += " OR " + "contact:" + searchString;
query += ")";
....
// The query will look like below, where<search_string> is some user inputted value
// (officialName:<search_string>*^3 OR deliverableName:<search_string>*^3 OR alias:<search_string>*^3 OR contact:<search_string>*)
I have setup a design doc and index using the Cloudant dashboard as follows:
{
"_id": "_design/bySearchPP-ddoc",
"_rev": "4-a91fc4ddeccc998c58adb487a121c168",
"views": {},
"language": "javascript",
"indexes": {
"bySearchPP-indx": {
"analyzer": {
"name": "perfield",
"default": "standard",
"fields": {
"alias": "simple",
"contact": "simple",
"deploymentTarget": "keyword",
"businessUnit": "keyword",
"division": "keyword",
"officialName": "simple",
"deliverableName": "simple",
"pid": "keyword"
}
},
"index": "function(doc) {
if (doc.docType === \"Page\") {
index(\"officialName\", doc.officialName, {\"store\":true, \"boost\":4.0});
index(\"deliverableName\", doc.deliverableName, {\"store\":true, \"boost\":3.0});
if (doc.aliases) {
for (var i in doc.aliases) {
index(\"alias\", doc.aliases[i], {\"store\":true, \"boost\":2.0});
}
}
if (doc.allContacts) {
for (var j in doc.allContacts) {
index(\"contact\", doc.allContacts[j], {\"store\":true, \"boost\":0.5});
}
}
index(\"deploymentTarget\", doc.deploymentTarget, {\"store\":true});
index(\"businessUnit\", doc.businessUnit, {\"store\":true});
index(\"division\", doc.division, {\"store\":true});
index(\"pid\", doc.pid.toLowerCase(), {\"store\":true});
}
}"
}
}
}
I am not sure if the sort is working and just not working how I want it to or if I have misconfigured something. Either way, any help would be greatly appreciated. -Doug
Solved my own issue w/ help from comments above. Apparently everything was setup correctly but once I debug per #markwatsonatx I could see the field I wanted wasn't being returned. Did some digging online and apparently for sort the field must be both indexed and NOT tokenized. Thus I checked my index and noticed that the filed was being analyzed by the Simple analyzer. Changed it to the Keyword and the sort works as expected. Hoep this helps someone.

How to retrieve the value of a key(nested) in JSON which is stored in mongoDB using JAVA?

Below is the JSON file from which I want to retrieve the phone number:
"_data" : {
"Variable key" : {
"Name" : "Hello World",
"Phone" : "Phone : 123-456-6789 ",
"Region" : "New York",
"Description" : ""
}
}
My Java Code is:
BasicDBObject query = new BasicDBObject();
BasicDBObject field = new BasicDBObject();
field.put("_data.Phone", 1);
DBCursor cursor = table.find(query,field);
String str;
while (cursor.hasNext()) {
BasicDBObject obj = (BasicDBObject) cursor.next();
str=cursor.curr().get("_data.Phone").toString();
System.out.println(str);
}
which will return null as I'm not considering the variable key.
My problem is there are many JSON files present in the mongo database each having different "Variable Key" and this key may change after sometime. As this key may change over time, how can I retrieve the phone number ?
Thank You !!
Which phone numbers do you want? Your query will return all documents and you are trying to project out just the phone number, but with an incorrect projection specification. If you want all phone numbers, just leave out the projection specification entirely or project on { "_data" : 1 }. If you want the phone numbers associated with specific variable keys, project those out using dot notation like { "_data.key_name.Phone" : 1 }. If you don't know the names of the keys that you want to project on, then that is your root problem that you need to solve before you ask MongoDB to return something that you don't know that you want (or that you don't want).

MongoDB nested documents searching

How do I search through mongodb documents where documents have nested documents. For example I have a collection of private messages. Each private message has two nested documents - one representing the sending user and the other representing the receiving use. Both nested documents have the form -
userID: 34343,
name: Joe Bloggs
I would like to be able to search for all mail messages sent by a user (e.g. search the sender user nested document).
I am using the java driver. Do I need to create a DBObject which represents the nested document?
Thanks
As i understand u have document structure like this:
{
"someProperty" : 1,
"sendingUser" : {
userID : 34343,
name : "Joe Bloggs"
},
"recivingUser" : {
userID : 34345,
name : "Joe Bloggs"
}
}
So if you need find sending user with userID = 34345 you just need do following(i just think that is so, because actually i am working with c# driver for mongo):
DBCollection coll = db.getCollection("privateMessages")
query = new BasicDBObject();
query.put("sendingUser.userID", new BasicDBObject("$eq", 34345));
cur = coll.find(query); // all documents with sendingUser.userID = 34345 will be //returned by cursor
Also check tutorial for java driver
For MongoDB Java Driver v3.2.2. You can do something like this:
FindIterable<Document> iterable = collection.find(Document.parse("{\"sendingUser.userID\": \"34343\"}"));
FindIterable<Document> iterable = collection.find(Document.parse("{\"sendingUser.name\": \"Joe Bloggs\"}"));
You can put the $eq inside the JSON style query string. Like { <field>: { $eq: <value> } }.

Categories