最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

How to make facet search by multiple nested fields in Elasticsearch Java API Client? - Stack Overflow

matteradmin7PV0评论

There are my example documents.

"id" : "1",
"title" : "test",
"description" : "test",
"price" : 100.0,
"category_id" : "1",
"characteristics" : [
  {
    "characteristic_id" : "1",
    "text_value" : "red"
  },
  {
    "characteristic_id" : "2",
    "numeric_value" : 15
  },
  {
    "characteristic_id" : "3",
    "numeric_value" : 20
  }
]

"id" : "2",
"title" : "test",
"description" : "test",
"price" : 200.0,
"category_id" : "1",
"characteristics" : [
  {
    "characteristic_id" : "1",
    "text_value" : "blue"
  },
  {
    "characteristic_id" : "2",
    "numeric_value" : 10
  },
  {
    "characteristic_id" : "3",
    "numeric_value" : 5
  }
]

And a query to my index must be like this. How can i write this using new Java Api Client for Elasticsearch?

GET product/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "nested": {
            "path": "characteristics",
            "query": {
              "bool": {
                "must": [
                  {
                    "term": {
                      "characteristics.characteristic_id": 1
                    }
                  },
                  {
                    "term": {
                      "characteristics.text_value": "blue"
                    }
                  }
                ]
              }
            }
          }
        },
        {
          "nested": {
            "path": "characteristics",
            "query": {
              "bool": {
                "must": [
                  {
                    "term": {
                      "characteristics.characteristic_id": 3
                    }
                  },
                  {
                    "range": {
                      "characteristics.numeric_value": {
                        "gte": 1,
                        "lte": 7
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        {
          "term": {
            "category_id": 1
          }
        },
        {
          "range": {
            "price": {
              "gt": 10.0,
              "lt": 500.0
            }
          }
        }
      ],
      "should": [
        {          
          "match": {
            "title": "te"
          }
        }
      ]
    }
  }
}

There is very little information in the official documentation. Should I even use this API if there is no normal documentation for it and write all the requests manually?

There are my example documents.

"id" : "1",
"title" : "test",
"description" : "test",
"price" : 100.0,
"category_id" : "1",
"characteristics" : [
  {
    "characteristic_id" : "1",
    "text_value" : "red"
  },
  {
    "characteristic_id" : "2",
    "numeric_value" : 15
  },
  {
    "characteristic_id" : "3",
    "numeric_value" : 20
  }
]

"id" : "2",
"title" : "test",
"description" : "test",
"price" : 200.0,
"category_id" : "1",
"characteristics" : [
  {
    "characteristic_id" : "1",
    "text_value" : "blue"
  },
  {
    "characteristic_id" : "2",
    "numeric_value" : 10
  },
  {
    "characteristic_id" : "3",
    "numeric_value" : 5
  }
]

And a query to my index must be like this. How can i write this using new Java Api Client for Elasticsearch?

GET product/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "nested": {
            "path": "characteristics",
            "query": {
              "bool": {
                "must": [
                  {
                    "term": {
                      "characteristics.characteristic_id": 1
                    }
                  },
                  {
                    "term": {
                      "characteristics.text_value": "blue"
                    }
                  }
                ]
              }
            }
          }
        },
        {
          "nested": {
            "path": "characteristics",
            "query": {
              "bool": {
                "must": [
                  {
                    "term": {
                      "characteristics.characteristic_id": 3
                    }
                  },
                  {
                    "range": {
                      "characteristics.numeric_value": {
                        "gte": 1,
                        "lte": 7
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        {
          "term": {
            "category_id": 1
          }
        },
        {
          "range": {
            "price": {
              "gt": 10.0,
              "lt": 500.0
            }
          }
        }
      ],
      "should": [
        {          
          "match": {
            "title": "te"
          }
        }
      ]
    }
  }
}

There is very little information in the official documentation. Should I even use this API if there is no normal documentation for it and write all the requests manually?

Share Improve this question edited Nov 17, 2024 at 15:32 Mark Rotteveel 110k230 gold badges156 silver badges225 bronze badges asked Nov 16, 2024 at 21:43 AssHandsAssHands 12 bronze badges 6
  • I have rolled back your edit. If you managed to solve your own problem, then post an Answer, do not add the solution to your Question. – Mark Rotteveel Commented Nov 17, 2024 at 15:32
  • sorry, but i cant, even when i use code block, it writes "Too long by N characters" @Mark Rotteveel – AssHands Commented Nov 18, 2024 at 11:46
  • That generally means that you have provide only code, and no explanation of your solution. – Mark Rotteveel Commented Nov 18, 2024 at 15:07
  • nope, still cant add a comment with code (i typed a lot of text before code block). nah, just leave a link to my solution in other forum @Mark Rotteveel – AssHands Commented Nov 18, 2024 at 17:21
  • You should not post a comment with code, you should post an answer, below in the "Your Answer" section. – Mark Rotteveel Commented Nov 19, 2024 at 10:42
 |  Show 1 more comment

1 Answer 1

Reset to default 0

Java code

        List<Query> filters = new ArrayList<>();

        if(requestPayload.getPriceTo() != 0) {
            filters.add(RangeQuery.of(r -> r
                            .field("price")
                            .gte(JsonData.of(requestPayload.getPriceFrom()))
                            .lte(JsonData.of(requestPayload.getPriceTo())))
                    ._toQuery());
        }

        if(requestPayload.getCategoryId() != null) {
            filters.add(TermQuery.of(t -> t
                    .field("category_id")
                    .value(requestPayload.getCategoryId()))
                    ._toQuery());
        }

        List<RangeQuery> rangeList = new ArrayList<>();
        for(var category : requestPayload.getFilters().getNumericValues()) {
            for (var numericValue : category.getValues()) {
                if (numericValue.getFrom() != null && numericValue.getTo() != null) {
                    rangeList.add(RangeQuery.of(r -> r
                            .field("characteristics.numeric_value")
                            .gte(JsonData.of(numericValue.getFrom()))
                            .lte(JsonData.of(numericValue.getTo()))));
                }
            }

            filters.add(NestedQuery.of(n -> n
                    .path("characteristics")
                    .query(q -> q
                            .bool(b -> {
                                b.must(m -> m
                                        .term(t -> t
                                                .field("characteristics.characteristic_id")
                                                .value(category.getCharacteristicId())));

                                for (RangeQuery rangeQuery : rangeList)
                                    b.should(s -> s.range(rangeQuery));

                                b.minimumShouldMatch("1");
                                return b;
                            })
                    ))._toQuery());
        }

        for(var category : requestPayload.getFilters().getTextValues()) {

            List<FieldValue> textValuesList = new ArrayList<>();
            for(var textValue : category.getValues()) {
                textValuesList.add(FieldValue.of(textValue));
            }

            TermsQueryField textValues = TermsQueryField.of(tf -> tf.value(textValuesList));
            if(!textValuesList.isEmpty()) {
                filters.add(NestedQuery.of(n -> n
                                .path("characteristics")
                                .query(q -> q
                                        .bool(b -> b
                                                .must(m -> m
                                                        .term(t -> t
                                                                .field("characteristics.characteristic_id")
                                                                .value(category.getCharacteristicId())))
                                                .must(m -> m
                                                        .terms(t -> t
                                                                .field("characteristics.text_value")
                                                                .terms(textValues))))))
                        ._toQuery());
            }
        }

        BoolQuery boolQuery = BoolQuery.of(b -> b
                .filter(filters)
                .should(s -> s
                        .match(m -> m
                                .field("title")
                                .query(requestPayload.getText()))));

        SearchResponse<ProductDocument> response = esClient.search(s -> s
                        .index("product")
                        .query(q -> q.bool(boolQuery)),
                ProductDocument.class);

        List<Hit<ProductDocument>> hits = response.hits().hits();
        for (Hit<ProductDocument> hit: hits) {
            System.out.println(hit.source());
        }

Json query

{
  "query": { 
    "bool": {
      
      "should": {
        "match": { "title": { "query": "te" } }
      },
      
      "filter": [
        {
          "range": { "price": { "gte": 1.0, "lte": 100.0 } }
        },

        {
          "term": { "category_id": "1" }
        },
        
        {
          "nested": {
            "path": "characteristics",
            "query": {
              "bool": {
                "must": [
                      { "term": { "characteristics.characteristic_id": "1" } },
                      { "terms": { "characteristics.text_value": ["red", "blue"] } }
                ]
              }
            }
          }
        },
        
        {
          "nested": {
            "path": "characteristics",
            "query": {
              "bool": {
                "must": [
                      { "term": { "characteristics.characteristic_id": "4" } },
                      { "terms": { "characteristics.text_value": ["yes"] } }
                ]
              }
            }
          }
        },
        
        {
          "nested": {
            "path": "characteristics",
            "query": {
              "bool": {
                "must": [
                      { "term": { "characteristics.characteristic_id": "2" } }
                ],
                "should": [
                      { "range": { "characteristics.numeric_value": { "gte": 1, "lte": 20 } } },
                      { "range": { "characteristics.numeric_value": { "gte": 21, "lte": 30 } } }
                ],
                "minimum_should_match": 1
              }
            }
          }
        }
        
      ] 
    }
  }
}
Post a comment

comment list (0)

  1. No comments so far