将动态模板应用于多种类型 - 用于管理令牌以进行排序

eri*_*ric 5 elasticsearch

我们在确定如何最好地管理我们的标记化和未标记化字段以进行搜索和排序时遇到了一些困难.我们的目标很简单:

  1. 支持部分单词搜索
  2. 支持对所有字段进行排序
  3. 我们的映射必须是动态的,客户在运行时添加新字段.

我们可以使用动态模板完成此任务.我们使用默认的标记生成器,自定义的ngram标记生成器和未经分析的标记生成器来存储字符串.映射:

curl -XPUT 'http://testServer:9200/test/' -d '{
        "settings": {
            "analysis": {
                "analyzer": {
                    "my_ngram_analyzer": {
                        "tokenizer": "my_ngram_tokenizer",
                        "filter": [
                            "lowercase"
                        ],
                        "type" : "custom"
                    },
                    "default_search": {
                        "tokenizer" : "keyword",
                        "filter" : [
                            "lowercase"
                        ]
                    }
                },
                "tokenizer": {
                    "my_ngram_tokenizer": {
                        "type": "nGram",
                        "min_gram": "3",
                        "max_gram": "100",
                        "token_chars": []
                    }
                }
            }
        },
        "mappings": {
            "TestObject": {
                "dynamic_templates": [
                    {
                        "metadata_template": {
                            "match_mapping_type": "string",
                            "path_match": "*",
                            "mapping": {
                                "type": "multi_field",
                                "fields": {
                                    "ngram": {
                                        "type": "{dynamic_type}",
                                        "index": "analyzed",
                                        "index_analyzer": "my_ngram_analyzer",
                                        "search_analyzer" : "default_search"
                                    },
                                    "{name}": {
                                        "type": "{dynamic_type}",
                                        "index": "analyzed",
                                        "index_analyzer" : "standard",
                                        "search_analyzer" : "default_search"
                                    },
                                    "sortable": {
                                        "type": "{dynamic_type}",
                                        "index": "analyzed",
                                        "analyzer" : "default_search"
                                    }
                                }
                            }
                        }
                    }
                ]
            }
        }
    }'
Run Code Online (Sandbox Code Playgroud)

我们实际上只保留未分析的字段用于排序和完全匹配(我们甚至称之为'可排序'.)这种配置使我们可以轻松获得部分单词搜索,如果查询是"包含"查询 - 我们将".ngram"附加到查询目标.我们遇到的问题是决定何时使用".sortable"后缀.例如,如果我们收到对dateUpdated进行排序的请求,则我们不想使用.sortable,因为该字段是日期.如果请求是对'name'进行排序,我们确实想要使用它,因为该字段是一个字符串,如果我们试图对'price'进行排序,则不使用它.

在排序之前检查字段类型的逻辑似乎有点麻烦(我们检查我们的模型,而不是检查elasticsearch中的类型).总是有一个'.sortable'字段,但我们可以' t通过下面的动态模板运行非字符串类型 - 布尔值和数字不能通过ngram过滤器运行.

有没有人建议我们如何总是有一个".sortable"字段进行排序,无论类型如何都不会被标记化?或者,对于我们没有看到的这类问题,您是否有更好的解决方案?提前致谢!

eri*_*ric 6

这真正归结为我们一直希望在每个映射字段上都有一个“可排序”字段(我们将其重命名为“未分析”,因为它有其他用途)。这样做的真正技巧,无需为每种类型添加新的动态模板,就是制作一个适用于除字符串以外的所有类型的动态模板。为此,您需要设置match_pattern为正则表达式:

           {
                "other_types": {
                    "match_mapping_type": "date|boolean|double|long|integer",
                    "match_pattern": "regex",
                    "path_match": ".*",
                    "mapping": {
                        "type": "multi_field",
                        "fields": {
                            "{name}": {
                                "type": "{dynamic_type}",
                                "index": "not_analyzed"
                            },
                            "unanalyzed": {
                                "type": "{dynamic_type}",
                                "index": "not_analyzed"
                            }
                        }
                    }
                }
            } 
Run Code Online (Sandbox Code Playgroud)

请注意,您还需要对“path_match”进行一些小的更改 - 您必须使用真正的正则表达式(而不是“*”,这是一个 ES 的“简单”表达式。)

这样做的一个缺点是我们正在增加索引的大小 - 我们将所有这些类型存储两次。不过,就我们的目的而言,我们的索引(我们有很多)有足够的增长空间,在进行排序或精确匹配查询之前避免对每个字段进行类型查找是值得的(只是总是使用 $ {fieldName}。未分析)。

  • 我意识到这已经很老了,但在当前版本的 Elasticsearch (8.x) 中,“match_mapping_type”似乎不支持正则表达式。即使指定了“match_pattern”:“regex”,当我尝试提供这样的多个 ord 值时,我也会收到“mapper_parsing_exception”。考虑到所有的赞成票,我认为这一定在某个时候发挥了作用。奇怪的是他们会删除这个功能。 (2认同)