最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

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

programmeradmin1浏览0评论

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
              }
            }
          }
        }
        
      ] 
    }
  }
}
发布评论

评论列表(0)

  1. 暂无评论