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

时间:2013-11-01 20:57:04

标签: elasticsearch

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

  1. 支持部分字词搜索
  2. 支持对所有字段进行排序
  3. 我们的映射必须是动态的,客户在运行时添加新字段。
  4. 我们可以使用动态模板完成此操作。我们使用默认的标记生成器,自定义的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"
                                        }
                                    }
                                }
                            }
                        }
                    ]
                }
            }
        }'
    

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

    在排序之前检查字段类型的逻辑看起来有点笨拙(我们检查我们的模型,而不是检查elasticsearch中的类型)。总是有一个'.sortable'字段,但是很好我们不能通过动态模板下面运行非字符串类型 - 布尔值和数字不能通过ngram过滤器运行。

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

1 个答案:

答案 0 :(得分:4)

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

           {
                "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"
                            }
                        }
                    }
                }
            } 

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

这样做的一个缺点是我们正在增加索引的大小 - 我们将所有这些类型存储两次。但是出于我们的目的,我们的索引(我们有很多)有很大的增长空间,在进行排序或完全匹配查询之前,避免必须在每个字段上查找类型是值得的(只需要总是使用$ {fieldName的} .unanalyzed)。