Find parent documents based on child doc value - java

We are using haschild query to find the parent documents based on the condition.
We have two types
funnels
pages
funnels sample doc
{
"funnel_id": "12345",
"path": "a -> b -> c"
}
{
"funnel_id": "56789",
"path": "a -> d"
}
** pages sample doc**
{
"_parent": "12345",
"visited_page": "/home"
}
{
"_parent": "12345",
"visited_page": "/cart"
}
{
"_parent": "12345",
"visited_page": "/cart"
}
Condition1:
Find parent doc based child doc "visited_page" value contains "home".
"must" : {
"has_child" : {
"query" : {
"regexp" : {
"url" : {
"value" : ".*home.*",
"flags_value" : 65535
}
}
},
"child_type" : "session_pages"
}
}
It works perfectly.
Condition2
Find parent doc based child doc "visited_page" value does NOT contains "home".
"must_not" : {
"has_child" : {
"query" : {
"regexp" : {
"url" : {
"value" : ".*home.*",
"flags_value" : 65535
}
}
},
"child_type" : "session_pages"
}
}
But this query returned wrong results.
Output of the query
{
"funnel_id": "12345",
"path": "a -> b -> c"
}
{
"funnel_id": "56789",
"path": "a -> d"
}
You can see the parent id(funnel_id:12345) child doc contains visited page with value "home". But that also returns.
Expected Result
{
"funnel_id": "56789",
"path": "a -> d"
}

I believe you are "must_not"ing in the wrong spot
try:
"must" : {
"has_child" : {
"query" : {
"regexp" : {
"url" : {
"must_not": {
"value" : ".*home.*"
},
"flags_value" : 65535
}
}
},
"child_type" : "session_pages"
}
}

Related

Stop nested resources being mapped to '/' - Spring Boot

I'm currently learning about Spring Boot and am undertaking a project where users can make posts, view those posts, etc.
A user's post(s) can be viewed via http://localhost:8080/users/{user_id}/posts and http://localhost:8080/users/{user_id}/posts/{post_id}
As a result I have the following UserPostController
#RestController
#RequestMapping("/users")
public class UserPostController {
#Autowired
private UserPostService postService;
#GetMapping("/{user_id}/posts")
public List<Post> retrieveUserPosts(#PathVariable int user_id) {
return postService.retrieveUserPostList(user_id);
}
#GetMapping("/{user_id}/posts/{post_id}")
public EntityModel<Post> retrieveUserPost(#PathVariable int user_id, #PathVariable int post_id) {
return postService.retrieveUserPost(user_id, post_id);
}
#PostMapping("/{user_id}/posts")
public ResponseEntity<Object> createUserPost(#PathVariable int user_id, #Valid #RequestBody Post post) {
return postService.saveUserPost(user_id, post);
}
}
Every request to the links work correctly. For example a GET request to http://localhost:8080/users/1/posts returns [{"id":1,"description":"This is a post"},{"id":2,"description":"This is another post"}], which is the expected action.
However, for some reason I am able to visit http://localhost:8080/posts which then returns a list of all posts:
{
"_embedded" : {
"posts" : [ {
"description" : "This is a post",
"_links" : {
"self" : {
"href" : "http://localhost:8080/posts/1"
},
"post" : {
"href" : "http://localhost:8080/posts/1"
},
"user" : {
"href" : "http://localhost:8080/posts/1/user"
}
}
}, {
"description" : "This another post",
"_links" : {
"self" : {
"href" : "http://localhost:8080/posts/2"
},
"post" : {
"href" : "http://localhost:8080/posts/2"
},
"user" : {
"href" : "http://localhost:8080/posts/2/user"
}
}
}, {
"description" : "This is yet another post",
"_links" : {
"self" : {
"href" : "http://localhost:8080/posts/3"
},
"post" : {
"href" : "http://localhost:8080/posts/3"
},
"user" : {
"href" : "http://localhost:8080/posts/3/user"
}
}
} ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/posts"
},
"profile" : {
"href" : "http://localhost:8080/profile/posts"
}
},
"page" : {
"size" : 20,
"totalElements" : 3,
"totalPages" : 1,
"number" : 0
}
}
Through HATEOAS I am able to also see available links of the format http://localhost:8080/posts/{user_id}/user which I have also not created methods for, but they still exist.
Is there a reason why these unwanted routes exist? If so how do I change this?
Thank you :)

Docx4j functionality to turn a document into JSON representation?

Is there a good way to convert a document into JSON representation to then display on a web page? (It is a requirement that the document is converted to JSON)
My Idea if there isn't a built in way to do this is to represent the Run/Paragraph structure as JSON Objects, but I feel like this wouldn't work as well once I start working with more complex Word Documents.
If you add:
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.11.3</version>
</dependency>
you can try something like:
import org.docx4j.Docx4J;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
public class ConvertOutJSON {
static String inputfilepath = System.getProperty("user.dir") + "/sample-docs/sample-docxv2.docx";
public static void main(String[] args)
throws Exception {
WordprocessingMLPackage wordMLPackage
= Docx4J.load(new java.io.File(inputfilepath));
String xml = wordMLPackage.getMainDocumentPart().getXML();
//System.out.println(xml);
XmlMapper xmlMapper = new XmlMapper();
JsonNode node = xmlMapper.readTree(xml);
ObjectMapper jsonMapper = new ObjectMapper();
//String json = jsonMapper.writeValueAsString(node);
String json = jsonMapper.writerWithDefaultPrettyPrinter().writeValueAsString(node);
System.out.println(json);
}
}
However in a quick test, I noticed some w:p nodes were not being emitted as JSON. I haven't looked to see whether they get dropped by Jackson at the readTree step or when ObjectMapper writes its output; you'll need to dig into Jackson to fix that.
It is currently producing output like:
{
"Ignorable" : "w14 wp14",
"body" : {
"p" : {
"rsidR" : "00D15781",
"rsidRDefault" : "00D15781",
"pPr" : {
"ind" : {
"left" : "0"
}
}
},
"tbl" : {
"tblPr" : {
"tblStyle" : {
"val" : "TableGrid"
},
"tblW" : {
"w" : "0",
"type" : "auto"
},
"tblLook" : {
"firstRow" : "1",
"lastRow" : "0",
"firstColumn" : "1",
"lastColumn" : "0",
"noHBand" : "0",
"noVBand" : "1",
"val" : "04A0"
}
},
"tblGrid" : {
"gridCol" : {
"w" : "3561"
}
},
"tr" : {
"rsidR" : "00D15781",
"tc" : {
"tcPr" : {
"tcW" : {
"w" : "7122",
"type" : "dxa"
},
"gridSpan" : {
"val" : "2"
}
},
"p" : {
"rsidR" : "00D15781",
"rsidRDefault" : "00945132",
"pPr" : {
"ind" : {
"left" : "0"
}
},
"r" : {
"t" : "Horizontal merge"
}
}
}
}
},
"sectPr" : {
"rsidR" : "00D15781",
"headerReference" : {
"type" : "default",
"id" : "rId12"
},
"pgSz" : {
"w" : "11907",
"h" : "16839",
"code" : "9"
},
"pgMar" : {
"top" : "720",
"right" : "720",
"bottom" : "720",
"left" : "720",
"header" : "720",
"footer" : "720",
"gutter" : "0"
},
"cols" : {
"space" : "720"
},
"docGrid" : {
"linePitch" : "360"
}
}
}
}

Elasticsearch results are not very accqurate with my mapping field query

Please find my mapping query below for the filename field.
PUT /articles
{
"settings" : {
"analysis" : {
"analyzer" : {
"filename_search" : {
"tokenizer" : "filename",
"filter" : ["lowercase"]
},
"filename_index" : {
"tokenizer" : "filename",
"filter" : ["lowercase","edge_ngram"]
}
},
"tokenizer" : {
"filename" : {
"pattern" : "[^\\p{L}\\d]+",
"type" : "pattern"
}
},
"filter" : {
"edge_ngram" : {
"side" : "front",
"max_gram" : 50,
"min_gram" : 1,
"type" : "edgeNGram"
}
}
}
},
"mappings" : {
"doc" : {
"properties" : {
"filename" : {
"type" : "text",
"search_analyzer" : "filename_search",
"analyzer" : "filename_index"
}
}
}
}
}
If am trying to query series1333372 doc623258 and am expecting karthik_series1333372_oracle_page_doc623258_v1_en-EU.pdf. But it's giving all the files which is having series1333372, not even checking for doc623258.
Please find my query below
get articles/_search
{
"query" : {
"match" : {
"filename" : "series1333372 doc623258"
}
}
}
I am inserting the following sample documents for testing from Kibana
POST articles/doc/1
{
"filename" : "karthik_series1333372_oracle_page_doc623258_v1_en-EU.pdf"
}
POST articles/doc/2
{
"filename" : "karthik_series1333372_sun_page_doc658_v1_en-EU.pdf"
}
POST articles/doc/3
{
"filename" : "series1333372_oracle_page_doc623_v1_en-US.pdf"
}
POST articles/doc/4
{
"filename" : "Engineering series1333372 valve_page doc6232 v1_en-US.pdf"
}
POST articles/doc/5
{
"filename" : "Machines_series1333372_page_doc62258_v1_en-US.pdf"
}
POST articles/doc/6
{
"filename" : "AIX series1333372 IBM page doc62358 v1_en-EU.pdf"
}
The default operator of match is OR. If you want all your terms to be present change it like this
GET articles/_search
{
"query" : {
"match" : {
"filename" : {
"query": "series1333372 doc623258",
"operator" : "and"
}
}
}
}

Elasticsearch Mustache optional parameters

I've been struggling with Elasticsearch templates, specifically in optional parameters. I'd like to add optional filters there. This is the code snippet I was trying out:
{
"filter" : {
"bool" : {
"must" : [
{{#ProductIDs.0}}
{ "terms" : { "Product.ProductID" : [{{#ProductIDs}}{{.}},{{/ProductIDs}}] } }
{{/ProductIDs.0}}
]
}
}
}
Of course I replaced " with \", uglified it, wrapped it up in { "template" :"_snippet_above_" }.
Now when I'm trying to call it using the following:
GET /statistic/_search/template
{
"template": {
"id": "test"
},
"params": {
"ProductIDs": [1,2]
}
}
It ignores parameter that I've provided, however when I try to do that in official mustache.io demo page - it works just fine.
I tried {{#ProductIDs.length}} option too - it didn't work out. After doing some research I've found out that there is one difference between mustache.js and mustache.java. I assumed that Elasticsearch uses JAVA version and it doesn't support length parameter, so I have to rely on isEmpty. So I've rewritten my query as follows:
{
"filter" : {
"bool" : {
"must" : [
{{^ProductIDs.isEmpty}}
{ "terms" : { "Product.ProductID" : [{{#ProductIDs}}{{.}},{{/ProductIDs}}] } }
{{/ProductIDs.isEmpty}}
]
}
}
}
Now when I query template with ProductIDs list - it works fine, however if I remove parameter, it brings no results. I assume it generates this:
{
"filter" : {
"bool" : {
"must" : [
{ "terms" : { "Product.ProductID" : [] } }
]
}
}
}
If I send empty array as Parameter - it works fine.
GET /statistic/_search/template
{
"template": {
"id": "test"
},
"params": {
"ProductIDs": []
}
}
I assume this happens because "ProductIDs" are undefined and not empty.
Is there a way to cath this condition in mustache.java so I can ignore these parameters?
tl;dr;
The issue is that if I don't specify parameter in my search request via template, my condition is rendered as an empty array, see this:
{
"filter" : {
"bool" : {
"must" : [
{ "terms" : { "Product.ProductID" : [] } }
]
}
}
}
If I pass empty array as a parameter, see this:
GET /statistic/_search/template
{
"template": {
"id": "test"
},
"params": {
"ProductIDs": []
}
}
It works as expected and doesn't generate filter condition as described in my template, because array doesn't have any data in it.
I want this:
GET /statistic/_search/template
{
"template": {
"id": "test"
},
"params": {
}
}
To work same as this:
GET /statistic/_search/template
{
"template": {
"id": "test"
},
"params": {
"ProductIDs": []
}
}
A workaround probably not the most elegant would be to change template query to be a should clause and add a match_all clause for empty list.
example:
{
"filter" : {
"bool" : {
"should" : [
{ "terms" : { "status" : [ "{{#ProductIDs}}","{{.}}","{{/ProductIDs}}"] }}
{{^ProductIDs}},
{"match_all":{}}
{{/ProductIDs}}
]
}
}
}
Didn't try it, but shouldn't something like this work?
{
"filter" : {
"bool" : {
"must" : [
{{#ProductIDs}}
{{^ProductIDs.isEmpty}}
{ "terms" : { "Product.ProductID" : [{{#ProductIDs}}{{.}},{{/ProductIDs}}] } }
{{/ProductIDs.isEmpty}}
{{#ProductIDs.isEmpty}}
{"match_all":{}}
{{/ProductIDs.isEmpty}}
{{/ProductIDs}}
{{^ProductIDs}}
{"match_all":{}}
{{/ProductIDs}}
]
}
}
}
Ain't pretty, maybe there's better way.
My suggestion to overcome this using a JSON template is:
{
"query": {
"bool": {
"must": [
{
"script": {
"script": {
"inline": "1==1 {{#ProductIDs}} && [\"{{#ProductIDs}}\",\"{{.}}\",\"{{/ProductIDs}}\"].contains(doc['Product.ProductID'].value){{/ProductIDs}}",
"lang": "painless"
}
}
}
]
}
}

Using Nested Projections in Spring Data REST

How to get expected output below where OrderProjection uses ItemProjection to render Items using Spring Data REST
GET /orders/1?projection=with_items
Projections :
#Projection(name = "summary", types = Item.class)
public interface ItemProjection {
String getName();
}
#Projection(name = "with_item", types = Order.class)
public interface OrderProjection {
LocalDateTime getOrderedDate();
Status getStatus();
Set<ItemProjection> getItems(); // this is marshalling as Set<Item> (full Item graph)
}
Currently getting as output:
{
"status" : "PAYMENT_EXPECTED",
"orderedDate" : "2014-11-09T11:33:02.823",
"items" : [ {
"name" : "Java Chip",
"quantity" : 1,
"milk" : "SEMI",
"size" : "LARGE",
"price" : {
"currency" : "EUR",
"value" : 4.20
}
} ],
"_links" : {
"self" : {
"href" : "http://localhost:8080/orders/1{?projection}",
"templated" : true
},
"restbucks:items" : {
"href" : "http://localhost:8080/orders/1/items"
},
"curies" : [ {
"href" : "http://localhost:8080/alps/{rel}",
"name" : "restbucks",
"templated" : true
} ]
}
}
Expected Output:
{
"status" : "PAYMENT_EXPECTED",
"orderedDate" : "2014-11-09T11:33:02.823",
"items" : [ {
"name" : "Java Chip"
} ],
"_links" : {
"self" : {
"href" : "http://localhost:8080/orders/1{?projection}",
"templated" : true
},
"restbucks:items" : {
"href" : "http://localhost:8080/orders/1/items"
},
"curies" : [ {
"href" : "http://localhost:8080/alps/{rel}",
"name" : "restbucks",
"templated" : true
} ]
}
}
You're running into DATAREST-394 which has been fixed a few days a go and will be making it into 2.2.2 and 2.3 RC1. It's already available in the snapshots for said versions, feel free to give them a spin.

Categories