1

I need to return a scored list of posts that contain as many tags that user provided as possible. Tags are stored in arrays as objects and user request contains an array of tag IDs (eg. ["a", "c"]). Single document looks something like this:

{
  id: 1,
  meta: {
    tags: [{id: "a", name: "Engine"}, {id: "b", name: "Street"}, {id: "c", name: "Sport"}]
  }
}

Sadly, term query returns posts in almost random order, as all of them have score 1.0:

{
  "query": {
    "bool": {
      "must": [
        {
          "terms": {
            "meta.tags.id.keyword": [
             "a", "c"
            ]
          }
        }
      ]
    }
  }
}

I assume that thing would be quite easy if all tags would be in a single string, as this would be normal full text search, but how to achieve something like this for object arrays?

Here is a mapping exception (dynamically created by NEST client):

"mappings" : {
  "properties" : {
    "categories" : {
      "properties" : {
        "id" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "name" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    },
    "description" : {
      "type" : "text",
      "fields" : {
        "keyword" : {
          "type" : "keyword",
          "ignore_above" : 256
        }
      }
    },
    "id" : {
      "type" : "text",
      "fields" : {
        "keyword" : {
          "type" : "keyword",
          "ignore_above" : 256
        }
      }
    },
    "inFavourite" : {
      "type" : "long"
    },
    "likes" : {
      "type" : "long"
    },
    "name" : {
      "type" : "text",
      "fields" : {
        "keyword" : {
          "type" : "keyword",
          "ignore_above" : 256
        }
      }
    },
    "photoPath" : {
      "type" : "text",
      "fields" : {
        "keyword" : {
          "type" : "keyword",
          "ignore_above" : 256
        }
      }
    },
    "meta" : {
      "properties" : {
        "tags" : {
          "properties" : {
            "id" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            },
            "name" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            },
          }
        },
      }
    },
    "userId" : {
      "type" : "text",
      "fields" : {
        "keyword" : {
          "type" : "keyword",
          "ignore_above" : 256
        }
      }
    },
    "viewCounter" : {
      "type" : "long"
    }
  }
}
  • Good question, would you mind sharing your index mapping, few sample and expected docs, so that its easy for community to reproduce your issue and provide working solution on your data-set. – Amit Feb 07 '21 at 03:50
  • I hava added a mapping. Docs are quite big, so it would be probably better to work on some custom examples. – Janusz Guzowski Feb 07 '21 at 09:01

1 Answers1

1
{
  "query": {
    "function_score": {
      "query": { "match_all": {} },
      "boost": "5", 
      "functions": [
        {
          "filter": { "match": { "test": "bar" } },
          "random_score": {}, 
          "weight": 23
        },
        {
          "filter": { "match": { "test": "cat" } },
          "weight": 42
        }
      ],
      "max_boost": 42,
      "score_mode": "max",
      "boost_mode": "multiply",
      "min_score": 42
    }
  }
}
KennetsuR
  • 704
  • 8
  • 17