ElasticSearch Search for specified value within `FromX` and `ToY` fields - elasticsearch

I want to query by specified value within range that made by value of two FromX and ToY fields, and search Title as text field by query_string query.
This example shows my goal:
Id | FromX | ToY | Title
-----------------------------
1 | 1 | 7 | Mohammad
2 | 2 | 3 | Ali
3 | 1 | 6 | MohammadAli
4 | 2 | 5 | MohammadReza
5 | 1 | 2 | AliReza
6 | 2 | 2 | Sayed Ali
example query:
value: 2 AND title: *Ali*
result for query:
Id | FromX | ToY | Title
-----------------------------
2 | 2 | 3 | Ali
3 | 1 | 6 | MohammadAli
5 | 1 | 2 | AliReza
6 | 2 | 2 | Sayed Ali
Update 1:
Add last record with Id=6 in the sample data and result.

The following query should give you what you expect:
{
"query": {
"bool": {
"filter": [
{
"range": {
"FromX": {
"lte": 2
}
}
},
{
"range": {
"ToY": {
"gte": 2
}
}
},
{
"query_string": {
"query": "*ali*"
}
}
]
}
}
}
However, not that prefix wildcards should be avoided at all cost as they will penalize the performance of your query. You should probably analyze your title field using ngrams and do normal match queries on the Title field, instead.

Related

How to get all unique records with the maximum value in column using LINQ

Learner | AssesmentId | Attempt
------------------------------------
Parker | 1 | 1
Parker | 1 | 2
Stark | 1 | 1
Rogers | 1 | 1
Rogers | 1 | 2
Parker | 1 | 3
Given this data, how do I get all the unique Student name with the highest Attempt?
I'm attempting to get this result:
Learner | AssesmentId | Attempt
------------------------------------
Parker | 1 | 3
Stark | 1 | 1
Rogers | 1 | 2
How can I do this in a single query in LINQ?
from la in _context.LearnerAssessments
where la.AssessmentId == assessmentId
&& learnerIds.Contains(la.LearnerId)
&& la.Attempt == {highest attempt}
var data = from list in _context.LearnerAssessments
group list by new
{
list.Learner,
list.AssesmentId
}
into g
select new
{
g.Key.Learner,
g.Key.AssesmentId,
Max= g.Max(x=>x.Attempt)
};
or using fluent API :
var data = _context.LearnerAssessments.GroupBy(l => new { l.Learner, l.AssesmentId }, (keys, item) => new
{
Key = keys,
MaxAttemp = item.Max(x => x.Attempt)
}).Select(x => new LearnerAssessment
{
Learner = x.Key.Learner,
Attempt = x.MaxAttemp,
AssesmentId = x.Key.AssesmentId
});

Grafana & Elastic - How to count sub array length

So I have a document that has two nested arrays i.e.
foo.bars[].baz[]
I am trying to figure out how I can use graphana to group by bars and give me a count of bar's for each bar. So it would look something like:
| bars.id| count|
| 1 | 10 |
| 2 | 15 |
| 3 | 20 |
What I have tried is the following:
Group by bars.id
Add a Sum metric for bars.baz.id
Override the script value to return 1
While this does give me the count of the bars, it does so for all bars in the document and not grouped by the bars.id i.e.
| bars.id| count|
| 1 | 45 |
| 2 | 45 |
| 3 | 45 |
Any help to achieve this would be very helpful.
Now if this can be done I have another more complex problem. I have another collection let's call it bobs that is a child of the root document. Now bobs isn't nested under the bars array but it has a bar.id field. I would also like to sum this based on that i.e.
{
bobs: [
{bar_id: 1},
{bar_id: 2},
],
bars: [
{id: 1, bazes: []},
{id: 2, bazes: []}
]
}
In this case I would also like in the table:
| bars.id| bobs.count|
| 1 | 1 |
| 2 | 1 |
| 3 | 0 |
Is this possible?

Laravel/Eloquent: Constrain nested eager load so as not to include empty parents

I have a relatively simple DB structure including countries, regions and depots. Each depot is assigned to an operator and a region:
operators
+----+------------+
| ID | name |
+----+------------+
| 1 | Operator 1 |
| 2 | Operator 2 |
+----+------------+
countries
+----+----------------+------+
| ID | country_id | code |
+----+----------------+------+
| 1 | United Kingdom | gb |
| 2 | France | fr |
+----+----------------+------+
regions
+----+-----------------+-------+
| ID | country_id (FK) | name |
+----+-----------------+-------+
| 1 | 1 | North |
| 2 | 1 | South |
| 3 | 1 | East |
| 4 | 1 | West |
| 5 | 2 | North |
| 6 | 2 | South |
| 7 | 2 | East |
| 8 | 2 | West |
+----+-----------------+-------+
depots
+----+----------------+------------------+-----------+
| ID | region_id (FK) | operator_id (FK) | name |
+----+----------------+------------------+-----------+
| 1 | 1 | 1 | Newcastle |
| 2 | 8 | 2 | Nantes |
+----+----------------+------------------+-----------+
I have set up their eloquent relationships successfully in the respective models.
I want to load each depot grouped into their respective regions and countries, and filtered by a specific operator.
$depots = Country::with('regions.depots')->whereHas('regions.depots', function($query) use ($opID) {
$query->where('operator_id',$opID);
})->get();
This does the trick, however as well as eager loading the depots, it's also eager loading all regions, including those without depots assigned to them. E.G. when the above is performed when $opID = 1, you get this result:
name: United Kingdom,
regions: [
{
name: North,
depots: [{
name: Newcastle
}]
}, {
name: South,
depots: []
}, {
name: East,
depots: []
}, {
name: West,
depots: []
}
]
What I would like is the above returned, but without the regions where there are no depots.
I have played around a lot with the constraints of both with and whereHas but cannot get the desired data structure. Why doesn't the below code have the desired effect?
$depots = Country::with(['regions.depots' => function($query) use ($opID) {
$query->where('depots.operator_id',$opID);
}])->get();
Is there any way at all of not eagerly loading the parent if the child doesn't exist? Or is it a case of performing the above query as I have it and then looping through the result manually?
EDIT
So after a few more hours I finally found a way to get my desired outcome. But it seems really dirty. Is this really the best way?
$depots = Country::whereHas('regions.depots', function($q) use ($opID) {
$q->where('operator_id',$opID);
})->with(['regions' => function($q) use ($opID) {
$q->with('depots')->whereHas('depots', function($q2) use ($opID) {
$q2->where('operator_id',$opID);
});
}])->get();
EDIT 2
So it turns out the first edit was actually querying the operator_id on everything but the depots table, which meant as soon as I added another depot owned by another operator in the same region, that showed up when I didn't want it to. The below seems even messier but does work. It's fun having conversations with myself ;) Hopefully it helps someone one day...
$depots = Country::has('regions.depots')
->with(['regions' => function($q) use ($opID) {
$q->with(['depots' => function($q2) use ($opID) {
$q2->where('operator_id',$opID);
}])->has('depots');
}])->get();
You can always use lazy loading:
$depots = Country::whereHas('regions.depots', function($q) use ($opID) {
$q->where('operator_id',$opID);
})->get()->load('regions.depots');

Elasticsearch index with jdbc driver

Sorry my english is bad
I am using elasticsearch and jdbc river. I have two table with many-to-many relations. For example:
product
+---+---------------+
| id| title |
+---+---------------+
| 1 | Product One |
| 2 | Product Two |
| 3 | Product Three |
| 4 | Product Four |
| 5 | Product Five |
+---+---------------+
product_category
+------------+-------------+
| product_id | category_id |
+------------+-------------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 4 |
| 2 | 5 |
+------------+-------------+
category
+---+---------------+
| id| name |
+---+---------------+
| 1 | Category One |
| 2 | Category Two |
| 3 | Category Three|
| 4 | Category Four |
| 5 | Category Five |
+---+---------------+
I want to use array type.
{
"id": 1,
"name": "Product one",
"categories": {"Category One", "Category Two", "Category Three"}
},
How should I write a sql?
Use elasticsearch-jdbc structured objects with sql, no need to group_concat:
SELECT
product.id AS _id,
product.id,
title,
name AS categories
FROM product
LEFT JOIN (
SELECT *
FROM product_category
LEFT JOIN category
ON product_category.category_id = category.id
) t
ON product.id = t.product_id
Since river has been deprecated since ES v1.5, maybe run a standalone importer is better.

Elasticsearch query time boosting produces result in inadequate order

The ES search result for the given search keyword one two three seems to be wrong after applying boost feature per keyword. Please help me modifying my "faulty" query in order to accomplish "expected result" below as I described. I'm on ES 1.7.4 with LUCENE 4.10.4
Boosting criteria -three is regarded as the most important keyword:
word - boost
---- -----
one 1
two 2
three 3
ES index content - just showing MySQL dump to make the post shorter
mysql> SELECT id, title FROM post;
+----+-------------------+
| id | title |
+----+-------------------+
| 1 | one |
| 2 | two |
| 3 | three |
| 4 | one two |
| 5 | one three |
| 6 | one two three |
| 7 | two three |
| 8 | none |
| 9 | one abc |
| 10 | two abc |
| 11 | three abc |
| 12 | one two abc |
| 13 | one two three abc |
| 14 | two three abc |
+----+-------------------+
14 rows in set (0.00 sec)
Expected ES query result - The user is searching for one two three. I'm not fussed about the order of equally scored records. I mean if record 6 and 13 switches places, I don't mind.
+----+-------------------+
| id | title | my scores for demonstration purposes
+----+-------------------+
| 6 | one two three | (1+2+3 = 6)
| 13 | one two three abc | (1+2+3 = 6)
| 7 | two three | (2+3 = 5)
| 14 | two three abc | (2+3 = 5)
| 5 | one three | (1+3 = 4)
| 4 | one two | (1+2 = 3)
| 12 | one two abc | (1+2 = 3)
| 3 | three | (3 = 3)
| 11 | three abc | (3 = 3)
| 2 | two | (2 = 2)
| 10 | two abc | (2 = 2)
| 1 | one | (1 = 1)
| 9 | one abc | (1 = 1)
| 8 | none | <- This shouldn't appear
+----+-------------------+
14 rows in set (0.00 sec)
Unexpected ES query result - Unfortunately, This is what I get.
+----+-------------------+
| id | title | _score
+----+-------------------+
| 6 | one two three | 1.0013864
| 13 | one two three abc | 1.0013864
| 4 | one two | 0.57794875
| 3 | three | 0.5310148
| 7 | two three | 0.50929534
| 5 | one three | 0.503356
| 14 | two three abc | 0.4074363
| 11 | three abc | 0.36586377
| 12 | one two abc | 0.30806428
| 10 | two abc | 0.23231897
| 2 | two | 0.12812772
| 1 | one | 0.084527075
| 9 | one abc | 0.07408653
+----+-------------------+
ES query
curl -XPOST "http://127.0.0.1:9200/_search?post_dev" -d'
{
"query": {
"bool": {
"must": {
"match": {
"title": {
"query": "one two three"
}
}
},
"should": [
{
"match": {
"title": {
"query": "one",
"boost": 1
}
}
},
{
"match": {
"title": {
"query": "two",
"boost": 2
}
}
},
{
"match": {
"title": {
"query": "three",
"boost": 3
}
}
}
]
}
},
"sort": [
{
"_score": {
"order": "desc"
}
}
],
"from": "0",
"size": "100"
}'
Some more test queries:
This query doesn't produce any result.
This query doesn't order correctly as seem here.
# Index some test data
curl -XPUT "localhost:9200/test/doc/1" -d '{"title": "one"}'
curl -XPUT "localhost:9200/test/doc/2" -d '{"title": "two"}'
curl -XPUT "localhost:9200/test/doc/3" -d '{"title": "three"}'
curl -XPUT "localhost:9200/test/doc/4" -d '{"title": "one two"}'
curl -XPUT "localhost:9200/test/doc/5" -d '{"title": "one three"}'
curl -XPUT "localhost:9200/test/doc/6" -d '{"title": "one two three"}'
curl -XPUT "localhost:9200/test/doc/7" -d '{"title": "two three"}'
curl -XPUT "localhost:9200/test/doc/8" -d '{"title": "none"}'
curl -XPUT "localhost:9200/test/doc/9" -d '{"title": "one abc"}'
curl -XPUT "localhost:9200/test/doc/10" -d '{"title": "two abc"}'
curl -XPUT "localhost:9200/test/doc/11" -d '{"title": "three abc"}'
curl -XPUT "localhost:9200/test/doc/12" -d '{"title": "one two abc"}'
curl -XPUT "localhost:9200/test/doc/13" -d '{"title": "one two three abc"}'
curl -XPUT "localhost:9200/test/doc/14" -d '{"title": "two three abc"}'
# Make test data available for search
curl -XPOST "localhost:9200/test/_refresh?pretty"
# Search using function score
curl -XPOST "localhost:9200/test/doc/_search?pretty" -d'{
"query": {
"function_score": {
"query": {
"match": {
"title": "one two three"
}
},
"functions": [
{
"filter": {
"query": {
"match": {
"title": "one"
}
}
},
"weight": 1
},
{
"filter": {
"query": {
"match": {
"title": "two"
}
}
},
"weight": 2
},
{
"filter": {
"query": {
"match": {
"title": "three"
}
}
},
"weight": 3
}
],
"score_mode": "sum",
"boost_mode": "replace"
}
},
"sort": [
{
"_score": {
"order": "desc"
}
}
],
"from": "0",
"size": "100"
}'

Resources