Возвращать совпадающие значения и количество значений, которые совпадают в запросеasticsearch - PullRequest
1 голос
/ 03 марта 2020

Предположим, у меня есть следующие два элемента в индексе эластичного поиска:

{
    "name": "bob",
    "likes": ["computer", "cat", "water"]
},
{
    "name": "alice",
    "likes": ["gaming", "gambling"]
}

Теперь я хотел бы запросить элементы, такие как computer, laptop или cat. (что соответствует bob, обратите внимание, что это должно быть точное совпадение строк)

В результате мне нужны совпадения, а также количество совпадений, поэтому я хотел бы получить следующее (так как он нашел компьютер и кошка, но не ноутбук или вода):

{
    "name": "bob",
    "likes": ["computer", "cat"],
    "likes_count": 2
}

Есть ли способ добиться этого с помощью одного запроса эластичного поиска? (обратите внимание, что я все еще застрял с ES2.4, но, надеюсь, скоро смогу обновить).

В идеале я также хотел бы отсортировать вывод по likes_count.

Спасибо вы!

1 Ответ

1 голос
/ 04 марта 2020

Лучшим способом было бы создать лайки как вложенный тип данных

Отображение

PUT index71
{
  "mappings": {
    "properties": {
      "name":{
        "type": "text"
      },
      "likes":{
        "type": "nested", 
        "properties": {
          "name":{
            "type":"keyword"
          }
        }
      }
    }
  }
}

Запрос:

GET index71/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "nested": {
            "path": "likes",
            "query": {
              "bool": {
                "must": [
                  {
                    "terms": {
                      "likes.name": [
                        "computer",
                        "cat",
                        "laptop"
                      ]
                    }
                  }
                ]
              }
            },
            "inner_hits": {}         ---> It will return matched elements in nested type
          }
        }
      ]
    }
  },
  "aggs": {
    "likes": {
      "nested": {
        "path": "likes"
      },
      "aggs": {
        "matcheLikes": {
          "filter": {
            "bool": {
              "must": [
                  {
                    "terms": {
                      "likes.name": [
                        "computer",
                        "cat",
                        "laptop"
                      ]
                    }
                  }
                ]
            }
          },
          "aggs": {
            "likeCount": {
              "value_count": {
                "field": "likes.name"
              }
            }
          }
        }
      }
    }
  }
}

Результат:

   "hits" : [
      {
        "_index" : "index71",
        "_type" : "_doc",
        "_id" : "u9qTo3ABH6obcmRRRhSA",
        "_score" : 1.0,
        "_source" : {
          "name" : "bob",
          "likes" : [
            {
              "name" : "computer"
            },
            {
              "name" : "cat"
            },
            {
              "name" : "water"
            }
          ]
        },
        "inner_hits" : {
          "likes" : {
            "hits" : {
              "total" : {
                "value" : 2,
                "relation" : "eq"
              },
              "max_score" : 1.0,
              "hits" : [
                {
                  "_index" : "index71",
                  "_type" : "_doc",
                  "_id" : "u9qTo3ABH6obcmRRRhSA",
                  "_nested" : {
                    "field" : "likes",
                    "offset" : 0
                  },
                  "_score" : 1.0,
                  "_source" : {
                    "name" : "computer"
                  }
                },
                {
                  "_index" : "index71",
                  "_type" : "_doc",
                  "_id" : "u9qTo3ABH6obcmRRRhSA",
                  "_nested" : {
                    "field" : "likes",
                    "offset" : 1
                  },
                  "_score" : 1.0,
                  "_source" : {
                    "name" : "cat"
                  }
                }
              ]
            }
          }
        }
      }
    ]
  },
  "aggregations" : {
    "likes" : {
      "doc_count" : 3,
      "matcheLikes" : {
        "doc_count" : 2,
        "likeCount" : {
          "value" : 2
        }
      }
    }
  }

Если лайки нельзя изменить на вложенный тип, необходимо использовать сценарии, которые повлияют на производительность

Отображение

{
  "index72" : {
    "mappings" : {
      "properties" : {
        "likes" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "name" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

Запрос:

{
  "script_fields": {  ---> It will iterate through likes and get matched values
    "matchedElements": {
      "script": "def matchedLikes=[];def list_to_check = ['computer', 'laptop', 'cat']; def do_not_return = true; for(int i=0;i<doc['likes.keyword'].length;i++){ if(list_to_check.contains(doc['likes.keyword'][i])) {matchedLikes.add(doc['likes.keyword'][i])}} return matchedLikes;"
    }
  },
  "query": {
    "bool": {
      "filter": {
        "bool": {
          "must": [
            {
              "terms": {
                "likes": [
                  "computer",
                  "laptop",
                  "cat"
                ]
              }
            }
          ]
        }
      }
    }
  },
  "aggs": {
    "Name": {
      "terms": {
        "field": "name.keyword",
        "size": 10
      },
      "aggs": {
        "Count": {
          "scripted_metric": {  --> get count of matched values
            "init_script": "state.matchedLikes=[]",
            "map_script": " def list_to_check = ['computer', 'laptop', 'cat']; def do_not_return = true; for(int i=0;i<doc['likes.keyword'].length;i++){ if(list_to_check.contains(doc['likes.keyword'][i])) {state.matchedLikes.add(doc['likes.keyword'][i]);}}",
            "combine_script": "int count = 0; for (int i=0;i<state.matchedLikes.length;i++) { count += 1 } return count;",
            "reduce_script": "int count = 0; for (a in states) { count += a } return count"
          }
        }
      }
    }
  }
}

Результат:

  "hits" : [
      {
        "_index" : "index72",
        "_type" : "_doc",
        "_id" : "wtqso3ABH6obcmRR0hSV",
        "_score" : 0.0,
        "fields" : {
          "matchedElements" : [
            "cat",
            "computer"
          ]
        }
      }
    ]
  },
  "aggregations" : {
    "Name" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "bob",
          "doc_count" : 1,
          "Count" : {
            "value" : 2
          }
        }
      ]
    }
  }

РЕДАКТИРОВАТЬ 1 Чтобы дать большее количество совпадений, измените условия запроса на предложение must. Каждое слагаемое в пункте must должно способствовать получению

GET index71/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "nested": {
            "path": "likes",
            "query": {
              "bool": {
                "should": [
                  {
                    "term": {
                      "likes.name": "computer"
                    }
                  },
                  {
                    "term": {
                      "likes.name": "cat"
                    }
                  },
                  {
                    "term": {
                      "likes.name": "laptop"
                    }
                  }
                ]
              }
            },
            "inner_hits": {}
          }
        }
      ]
    }
  },
  "aggs": {
    "likes": {
      "nested": {
        "path": "likes"
      },
      "aggs": {
        "matcheLikes": {
          "filter": {
            "bool": {
              "must": [
                {
                  "terms": {
                    "likes.name": [
                      "computer",
                      "cat",
                      "laptop"
                    ]
                  }
                }
              ]
            }
          },
          "aggs": {
            "likeCount": {
              "value_count": {
                "field": "likes.name"
              }
            }
          }
        }
      }
    }
  }
}

Результат

  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.5363467,
    "hits" : [
      {
        "_index" : "index71",
        "_type" : "_doc",
        "_id" : "u9qTo3ABH6obcmRRRhSA",
        "_score" : 1.5363467,
        "_source" : {
          "name" : "bob",
          "likes" : [
            {
              "name" : "computer"
            },
            {
              "name" : "cat"
            },
            {
              "name" : "water"
            }
          ]
        },
        "inner_hits" : {
          "likes" : {
            "hits" : {
              "total" : {
                "value" : 2,
                "relation" : "eq"
              },
              "max_score" : 1.7917595,
              "hits" : [
                {
                  "_index" : "index71",
                  "_type" : "_doc",
                  "_id" : "u9qTo3ABH6obcmRRRhSA",
                  "_nested" : {
                    "field" : "likes",
                    "offset" : 1
                  },
                  "_score" : 1.7917595,
                  "_source" : {
                    "name" : "cat"
                  }
                },
                {
                  "_index" : "index71",
                  "_type" : "_doc",
                  "_id" : "u9qTo3ABH6obcmRRRhSA",
                  "_nested" : {
                    "field" : "likes",
                    "offset" : 0
                  },
                  "_score" : 1.2809337,
                  "_source" : {
                    "name" : "computer"
                  }
                }
              ]
            }
          }
        }
      },
      {
        "_index" : "index71",
        "_type" : "_doc",
        "_id" : "pr-lqHABcSMy6UhGAWtW",
        "_score" : 1.2809337,
        "_source" : {
          "name" : "bob",
          "likes" : [
            {
              "name" : "computer"
            },
            {
              "name" : "gaming"
            },
            {
              "name" : "gambling"
            }
          ]
        },
        "inner_hits" : {
          "likes" : {
            "hits" : {
              "total" : {
                "value" : 1,
                "relation" : "eq"
              },
              "max_score" : 1.2809337,
              "hits" : [
                {
                  "_index" : "index71",
                  "_type" : "_doc",
                  "_id" : "pr-lqHABcSMy6UhGAWtW",
                  "_nested" : {
                    "field" : "likes",
                    "offset" : 0
                  },
                  "_score" : 1.2809337,
                  "_source" : {
                    "name" : "computer"
                  }
                }
              ]
            }
          }
        }
      }
    ]
  },
  "aggregations" : {
    "likes" : {
      "doc_count" : 6,
      "matcheLikes" : {
        "doc_count" : 3,
        "likeCount" : {
          "value" : 3
        }
      }
    }
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...