Filtering products index in elasticsearch by user - elasticsearch

I have an index of products. They have regular fields such as id, name, brand etc. Querying this index is working great, however I want to limit the products which are returned for specific users.
Say I have 5 products who’s IDs go from 1-5
Id: 1, name: “Product One”, brand: “Fake Brand”
Id: 2, name: “Product Two”, brand: “Fake Brand”
Id: 3, name: “Product Three”, brand: “Fake Brand”
Id: 4, name: “Product Four”, brand: “Fake Brand”
Id: 5, name: “Product Five”, brand: “Fake Brand”
If there’s no filter, and I search for brand: “Fake Brand”, I get 5 results.
But I want to add this functionality: Say I have two users. User 1 is only able to “see” product IDs 1, 2, and 5. And User 2 is only able to “see” a different subset, say, product IDs 1, 2, 4 and 5.
So if user 1 searches for brand: “Fake Brand”, he only gets back product with IDs 1, 2, and 5. Where as if user 2 searches for brand: “Fake Brand”, he only gets back products with IDs 1, 2, 4 and 5.
Is there a way to add a “user id” to this products query and then store somewhere else what products a user is able to see?
In SQL I would probably have a different table storing what products each user can see and then just do a join. But using ES I think I either have to have two separate indexes or to use nested or has_child/has_parent queries but I’m not entirely sure how to implement it.

Related

fetch perticular number of documents satisfying multiple conditions - Elasticsearch

I have a Elasticsearch index for an information of fruits as below
GET fruits/fruits_data/_search
[{ id: 1,
name: apple},
{ id: 2,
name: mango},
{ id: 3,
name: apple},
{ id: 4,
name: banana},
{ id: 5,
name: apple},
{ id: 6,
name: mango},
{ id: 7,
name: pineapple},
{ id: 8,
name: jackfruit}]
Now I need to fetch 7 fruits as per the priority (below):
{"apple": 3, "banana": 3, "mango": 2, "guava": 2, "pineapple": 1, "jackfruit": 1}
Here the key indicates the fruit to be fetched and valueindicates the maximum number of the document to be fetched.
This means I need to fetch maximum 3 apple, 3 banana and 1 mango and I can ignore the others in priority hash when I have required number of fruits. But here I have only 1 banana in my ES index so I need to fetch maximum 3 apple, 1 banana, 2 mango and 1 pineapple (Since guava is not present in index we need to ignore it.
Is there a way to fetch fruits like this in ES in a single query. I don't want to use multiple queries.
Thanks
It is not possible to fetch results directly,Try using Aggregation in elasticsearch. You can refer to link below,
[https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations.html]

Search in Elasticsearch objects from non blocked user

In Elaasticsearch we have 3 collections, users, products and blocked_users.
user[
{id: 1, first_name: “John”, last_name:“Snow”, …}
{id: 2, first_name: “Sarah”, last_name:“Connor”, …}
{id: 2, first_name: “Arnold”, last_name:“Schwarzenegger”, …}
]
products[
{id: 1, user_id: 3, title:“Apple”}
]
blocked_users[
{user_id: 2, blocked_user_id: 3} // this mean user with id 2 blocked user with id 3
]
I want to search products by title, but I don't want to show products of blocked users.
So, when user with id 1 search he will get a response with 1 product
when user with id 2 search 0 products is expected, because product user id is 3, but user with id 2 blocked this user
How should be query?

Displaying Duplicate Records as One in Rails

I have a table of sales information, each product has twelve records for each month of the year. The only unique value is the sale total.
#<AccountMarginTarget id: 1, product_id: "123", sales: 2000>
#<AccountMarginTarget id: 2, product_id: "123", sales: 50>
#<AccountMarginTarget id: 2, product_id: "123", sales: 37>
#<AccountMarginTarget id: 2, product_id: "22", sales: 47>
#<AccountMarginTarget id: 2, product_id: "22", sales: 74>
I know I can retrieve consolodated data using .group, eg:
YearSales.group(:product_id).sum(:sale_total)
But when it comes to displaying all in the view, it's troublesome to have a list of 12 records. I've looked at .join .group .uniq etc. - but I'm still puzzled to as what the best method for only listing duplicates once?
Apologies for any naivety!
So, I've figured this out and feel a little dumb as to how easy it was to achieve. As I'm a Jr I'd appreciate any improvements on the below :) I'll update as my I review my code.
As I have many duplicates in my table, first I need to single them out
unique_ids = #sale_records.map(&:product_id).uniq.map
then I iterate through the unique_id's and retrieve the first result from the database that matches it:
#unique_product_sale_records = unique_ids.collect.each do | unique_id |
SalesRecord.where(product_id: unique_id).first
end

How to delete RethinkDB documents that cannot be joined?

I have a tables Person and Property. Each one has its own id. In addition, properties have their human owner, hence have a field person_id which "points" to the id in the Person table.
This is an example of three people that have some things. For some reason, person with id=3 was deleted. However, he/she still owns properties with id in [4,5,6].
Person (1k documents)
=====================
{id: 1, name: John, age: 25}
{id: 2, name: Peter, age: 28, pet: cat}
{id: 4, name: Alice}
...
Property (120k documents)
=========================
{id: 1, person_id: 1, name: house}
{id: 2, person_id: 1, name: car, color: blue}
{id: 3, person_id: 2, name: phone}
{id: 4, person_id: 3, name: house}
{id: 5, person_id: 3, name: watch, size: big}
{id: 6, person_id: 3, name: table: material: wood}
...
The question is "How to delete the properties documents that no longer have an existing person they belong to?", i.e. in this case "How to delete properties with id in [4,5,6]?"
person_id is a secondary index.
My thoughs were like somehow extract the properties ids that don't match any persons and than delete them. However, I have no idea how to achieve that.

'Associated' data in ElasticSearch

For an ecommerce platform, we're looking to index products. Default fields are simple as: name_en, name_de, name_fr, description. But, price and stock are dependant on another value:
Product A, for webshop 1, has price = 1.99, stock = 10, and fits under categories 1, 10, and 50.
Product A, for webshop 2, has price = 5.99, stock = 5, and categories 9, 90, and 500.
I was thinking of nested objects, but is that even an option?
- name_en: Product A
- description_en: Product A description
- webshops: [{
- key: webshop_id
value: 1
- key: price
value: 1.99
- key: stock
value: 10
- key: categories
value: [1, 10, 50]
},{
- key: webshop_id
value: 2
- key: price
value: 5.99
- key: stock
value: 5
- key: categories
value: [9, 90, 500]
}
]
Is it easy querying like this? Can we easily get the entire document, with the values where webshop.key.webshop_id.value = 1, or webshop.key.categories.value = 500?
Is my thinking wrong, any pointers in the right direction?
You can nest as you did, but it will get difficult to update the price or stock of a product in a single webshop, because you'll have to reindex the whole webshops array. There are ways to around it, but that's convoluted.
Instead of having a nested structure, you can also denormalize the webshop part and simply include the price, stock and categories fields in the documents like this.
Document 1:
- name_en: Product A
- description_en: Product A description
- webshop_id: 1
- price: 1.99
- stock: 10
- categories: [1, 10, 50]
Document 2:
- name_en: Product A
- description_en: Product A description
- webshop_id: 2
- price: 5.99
- stock: 5
- categories: [9, 90, 500]
Then in your queries you can simply add a constraint for webshop = 1 or webshop = 2 (or both) depending on which webshop you're querying against. It's also much easier to update the price, stock and categories of a product in a specific shop, all you have to do is update the corresponding document.
This means that your product data (name, description, etc) will be copied once per webshop but it's not a big deal usually (pretty common in the NoSQL world), you just have to update 2 documents instead of a single, but _bulk will help there. At least, when you add new webshops, you don't need to reindex all your data (!!!) and you change the prices, stocks in one webshop without interfering with the others.
You can also use the parent/child relationship capability.
You must define two document types: product and webshop
In the mapping, you must define the relationship like that : https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-parent-field.html
{
"webshop" : {
"_parent" : {
"type" : "product"
}
}
}
Like that you can index all the products in the product type. Then you can index all the webshop details related to the product.
You can use the query/filters to retrieve the webshop details related to a product.
Like that you have real different documents that can be queried separately.

Resources