ElasticSearch:搜索flat属性中所有键值相同的所有文档

vpfxa7rd  于 2022-12-03  发布在  ElasticSearch
关注(0)|答案(1)|浏览(134)

让我们假设我在elasticsearch中有两种文档,当“map”是flaten类型时:1.

doc1: {
"name": "foo1",
"map": {
  "key1": 100,
  "key2": 100
  }
}
doc2: {
"name": "foo2",
"map": {
  "key1": 100,
  "key2": 90
  }
}

我是否可以搜索elasticsearch来获取所有“map”属性(例如key 1、key 2)的值都相同(例如key 1 =100、key 2 =100)的文档,这样它就可以返回doc 1,而无需事先知道“map”属性下存在哪些属性?
谢谢你!

yhuiod9q

yhuiod9q1#

是的。实际上有两种方法可以实现你的目标:
1.通过ingest pipeline向文档添加标志字段,然后针对此新字段运行常规筛选器**(推荐)**
1.通过runtime fields动态生成标志字段

#1是推荐的方法,因为对每个查询迭代每个文档的伸缩性不好。创建一个标志字段效率更高。假设您有两个文档:

POST test_script/_doc
{
  "name": "foo1",
  "map": {
    "key1": 100,
    "key2": 100
  }
}

POST test_script/_doc
{
  "name": "foo2",
  "map": {
    "key1": 100,
    "key2": 90
  }
}

1.通过摄取管道向文档添加标志字段(推荐)

创建摄取管道:

PUT _ingest/pipeline/is_100_field
{
  "processors": [
    {
      "script": {
        "source": "def keys_100 = 0;\ndef keys = ctx['map'].keySet();\n\nfor (key in keys) {\n    if(ctx['map'][key] == 100){\n        keys_100 = keys_100 + 1;\n    }\n}\n\nctx.is_100 = keys.size() == keys_100;",
        "ignore_failure": true
      }
    }
  ]
}

现在,您可以使用此摄取管道重新索引数据,或配置以将其应用于每个文档:
重新索引:

POST your_index/_update_by_query?pipeline=is_100_field

摄入

POST your_index/_doc?pipeline=is_100_field

这将生成以下文档模型

{
  "took": 0,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "max_score": 1,
    "hits": [
      {
        "_index": "test_script",
        "_id": "78_AvoQB5Gw0WET88nZE",
        "_score": 1,
        "_source": {
          "name": "foo1",
          "map": {
            "key1": 100,
            "key2": 100
          },
          "is_100": true
        }
      },
      {
        "_index": "test_script",
        "_id": "8s_AvoQB5Gw0WET8-HYO",
        "_score": 1,
        "_source": {
          "name": "foo2",
          "map": {
            "key1": 100,
            "key2": 90
          },
          "is_100": false
        }
      }
    ]
  }
}

现在,您可以运行常规过滤器,这是最有效的方法:

GET test_script/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "term": {
            "is_100": true
          }
        }
      ]
    }
  }
}

通过运行时字段动态生成标志字段

脚本是相同的,但是现在字段将动态生成,而不是在数据中摄取。我们可以将此字段添加到Map或查询中:
Map:

PUT test_script_runtime/
{
  "mappings": {
    "runtime": {
      "is_100": {
        "type": "boolean",
        "script": {
          "source": """
          def keys_100 = 0;
          def keys = params._source['map'].keySet();
          
          for (key in keys) {
              if(params._source['map'][key] == 100){
                  keys_100 = keys_100 + 1;
              }
          }
          
          emit(keys.size() == keys_100);
          """
        }
      }
    },
    "properties": {
      "map": {"type": "object"},
      "name": {"type": "text"}
    }
  }
}

查询

GET test_script/_search
{
  "runtime_mappings": {
    "is_100": {
      "type": "boolean",
      "script": {
        "source": """
        def keys_100 = 0;
        def keys = params._source['map'].keySet();
        
        for (key in keys) {
            if(params._source['map'][key] == 100){
                keys_100 = keys_100 + 1;
            }
        }
        
        emit(keys.size() == keys_100);
        """
      }
    }
  },
  "query": {
    "bool": {
      "filter": [
        {
          "term": {
            "is_100": true
          }
        }
      ]
    }
  }
}

如果您决定对运行时字段进行索引,则可以轻松完成:https://www.elastic.co/guide/en/elasticsearch/reference/current/runtime-indexed.html

相关问题