understanding Elasticsearch query with elasticsearch-model ruby gem - ruby-on-rails

I have a search form where I want someone to choose to enter in a query or not, then optionally enter in some sort of filter to get a result. So, dealing with 2 fields name and city, let's say someone searches "billy", and "Las Vegas". The user searching knows there is a name that has "billy" in it, but don't know if it's a first, middle, or last, or maybe it was a street name... The one thing the user knows for sure is that the record is in the city "Las Vegas".
Here is my query hash that gives me 0 results.
{
query: {
query_string: {
query: 'billy'
}
},
filter: {
and: [
{term: {city: 'Las Vegas'}}
]
}
}
What am I missing here?

Just came across this. Instead of using the elasticsearch-model gem, use the searchkick gem. Tons easier to integrate and query.
Person.search("billy", where: {city: 'Las Vegas'})
This still uses elasticsearch, and returns the exact results I was looking for!

Related

How to only return subset of larger query in GraphQL without returning the whole thing?

I am new to GraphQL and trying to understand how to only return a subsection of the resulting query. For example, here is my cypher query in Neo4j:
MATCH (u:User)-[HAS_FRIEND]-(f:User)
WHERE u.name = "Joe"
RETURN f.name
Notice how the above query only returns the friend names.
GraphQL
Here's a sample of GraphQL version of the above cypher query.
Input
{
"where": {
"name": "Joe"
}
}
Query
query Query($where: NameWhere) {
names(where: $where) {
name
friends {
name
}
}
}
Expected Output
Obviously, I expect output to include friends name array and the name of the user having the friend. But, what if I only want the friends array like the cypher query gives me?
While this is a simple example, I am using a graph database that has a series of connections and my nesting is looking pretty deep, but I only really need a subquery from the result. A great example is with localization - I don't need the country and language (locale), etc. in every query; I only want the subquery result (e.g. the spelling in UK/ENG is colour and in US/ENG is color).
Neo4j offers a Javascript GraphQL library that is able to handle your use case (and many more)!
Please have a look at the documentation for information on how to get started. See even the example queries, where this one is fairly close to what you are looking for.
Anyhow, the GraphQL query provided above, using the #neo4j/graphql library, could look like so:
query Query {
users (where: { name: "Joe" }) {
friends {
name
}
}
}
(Note that the where parameter ("Joe") is provided in-line in this case)

controlling search results position SearchKick

Im using SearchKick which is great, Im migrating from a really bad search implementation and the product team didn't give me much trust as such before migrating to SearchKick and doing an overhaul to our search, they made me add hardcoded query results, so they can say for this search input I want this product to come up first. right now Im taking the query results that answer a certain the requested query from the db and add them at the top ( I don't care if you want the result at position 48, if there are 4 hard coded results it will be the 4th). although if possible it would be nice to do put them in the middle.
What is the cleanest way to do it with SearchKick, so that the querying will happen inside elastic ( index the hardcoded results in the product to do so )
I have 2 models Product and QueryResult, QueryResult contains a product, a query string & a wanted_rank
in my Product model I do have a method to get search results that looks something like this:
def get_search_results(query_string)
# get search results from elastic using searchkick
search_results = Product.search(query_string)
# get hardcoded results matching this query
hardcoded_results = QueryResults.where(query: query).order(:wanted_rank).map(&:product)
# remove hardcoded results from search_results
search_results = search_results - hardcoded_results
# return results where hardcoded results are first
hardcoded_results + search_results
end
In the end I want all the search logic to happen over elastic including inserting hardcoded search results
So after some very helpful comments and more search I found a solution.
first of all my first mistake was to try to fix it using boosts instead of order, to do so we index all QueryResults of a specific product under a field called called query_results.
for a product x with query results:
{
query: 'foo',
wanted_rank: 1,
},
{
query: 'bar',
wanted_rank: 2,
}
I will index:
{
name: 'x',
query_results: {
'foo': 1,
'bar': 2
}
}
than when searching, given a attribute named query, I will do as follow:
Product.search(
query,
order: [
{ "query_results.#{query}": { unmapped_type: :long },
{ _score: :desc }
]
)
2 important things to notice:
use unmapped_type this will tell elastic what mapping to use when there is no mapping, each random query that does not have a query result ( which is most of them ) will have no mapping for "query_results.#{query}" because it wont be indexed, as such we add unmapped_type to tell elastic if you have no mapping act like its long.
both when searching and when saving the db I downcase and strip query so it will match properly.
also I index the queries under another field and do a search over it with low weight to make sure that the product will come up for that query.

Grouped facets with elasticsearch

I'm looking for a way to display my facets in a grouped list. For example i have some users and a facet to filter by country, this gives me:
Country
Holland (5)
England (2)
Egypt (5)
Rwanda (2)
And what i would like to have is:
Europe
Holland (5)
England (2)
Africa
Egypt (5)
Rwanda (2)
I'm using the Tire gem in a Rails application, my models and relations are like this: http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-option_groups_from_collection_for_select
I've googled for an example on this for hours, just can't find anything for nested /grouped facets what makes sense to me in Elasticsearch. Hope someone can help me in the right direction! Many thanks in advance!
Daniel
You can probably handle this by indexing the data in two ways and then just parse the outout. Use the "object" version to apply filters, and get your parsing version as a facet to display filters.
For example:
"mydocument":{
"attributes":[
"location":{
{"continent":"europe",
"country":"england"
},
"fur_style":"long"
],
"facets":[
{"location":"Europe##england"},
{"fur_style":"long"
]
}
when you get your data back, you'll have:
"facets":[
{"location":"Europe##england",
"total":5},
{"location":"africa##egypt",
"total":7}
{"fur_style":"long",
"total":3}
etc etc
]
In your application, you just have to loop through and break apart the terms using the ## delimiter (or whatever you want it to be).

MongoDB Substring matching query

My application is trying to match an incoming string against documents in my Mongo Database where a field has a list of keywords. The goal is to see if the keywords are present in the string.
Here's an example:
Incoming string:
"John Doe is from Florida and is a fan of American Express"
the field for the documents in the MongoDB has a value such as:
in_words: "georgia,american express"
So, the database record has inwords or keywords separate by comman and some of them are two words or more.
Currently, my RoR application pulls the documents and pulls the inwords for each one issuing a split(',') command on the inwords, then loops through each one and sees if it is present in the string.
I really want to find a way to push this type of search into the actual database query in order to speed up the processing. I could change the in_words in the database to an array such as follows:
in_words: ["georgia", "american express"]
but I'm still not sure how to query this?
To Sum up, my goal is to find the person that matches an incoming string by comparing a list of inwords/keywords for that person against the incoming string. And do this query all in the database layer.
Thanks in advance for your suggestions
You should definitely split the in_words into an array as a first step.
Your query is still a tricky one.
Next consider using a $regex query against that array field.
Constructing the regex will be a bit hard since you want to match any single word from your input string, or, it appears any pair of works (how many words??). You may get some further ideas for how to construct a suitable regex from my blog entry here where I am matching a substring of the input string against the database (the inverse of a normal LIKE operation).
You can solve this by splitting the long string into seperate tokens and put them in to the separate array. And use $all query to effectively find the matching keywords.
Check out the sample
> db.splitter.insert({tags:'John Doe is from Florida and is a fan of American Express'.split(' ')})
> db.splitter.insert({tags:'John Doe is a super man'.split(' ')})
> db.splitter.insert({tags:'John cena is a dummy'.split(' ')})
> db.splitter.insert({tags:'the rock rocks'.split(' ')})
and when you query
> db.splitter.find({tags:{$all:['John','Doe']}})
it would return
> db.splitter.find({tags:{$all:['John','Doe']}})
{ "_id" : ObjectId("4f9435fa3dd9f18b05e6e330"), "tags" : [ "John", "Doe", "is", "from", "Florida", "and", "is", "a", "fan", "of", "American", "Express" ] }
{ "_id" : ObjectId("4f9436083dd9f18b05e6e331"), "tags" : [ "John", "Doe", "is", "a", "super", "man" ] }
And remember, this operation is case-sensitive.
If you are looking for a partial match, use $in instead $all
Also you probably need to remove the noise words('a','the','is'...) before insert for accurate results.
I hope it is clear

filtering relationships in neo4js

I am using neo4js to store users as nodes with property as user_id. There is a friend relation from user1 to user 2.
I am trying to find the incomming friend connections on node user2(user_id =2) which are comming from node with user_id=1.
I am using the neography library for the same.
https://github.com/maxdemarzi/neography/
u2 = Neography::Node.(id)
u2.outgoing(:friends).filter("..........")
I am not sure what exact filter should be given so that I can filter out the relationships comming from node(s) with user_id=1.
Regards,
Pankaj
You can use a traversal in neo4js to find those relationships.
This is untested code, but you want to do something like this:
var promise = somenode.traverse({
"prune_evaluator": {
"language": "javascript",
"body": "position.endNode().getId()!=2;" // Note that this is a string
}},
neo4j.traverse.RETURN_RELATIONSHIPS);
promise.then(function(relationships) {
console.log(relationships);
});
The first argument to the traverse method is a traversal object, for full docs on what you can put there, see http://docs.neo4j.org/chunked/snapshot/rest-api-traverse.html

Resources