我正在评估ElasticSearch是否能够满足我建立的新系统的需求。它看起来很神奇,所以我非常希望我能找到一种有效的映射策略。
在此系统中,管理员可以动态定义与文档关联的字段。因此,给定类型(在弹性搜索意义上的单词)可以包含任意数量的字段,我不知道提前的名称。每个字段可以是任何类型:int,date,string等。
示例文档可能如下所示:
{
"name": "bob",
"age": 22,
"title": "Vice Intern",
"tagline": "Ask not what your company can do for you, but..."
}
请注意,有2个字符串字段。真棒。我的问题是,我想要"标语"待分析,但我不想" title"待分析。
请记住,我不会提前知道这些字段的名称。并且每种类型可能有多个字段。所以可能有10个不同名称的字符串字段,其中3个应该被分析,其中7个不应该分析。
我的另一个要求是管理员给出字段的名称也应该是他们可以搜索的内容。因此,例如,如果他们想找到所有有话要说的副实习生,那么lucene查询可能是:
+title:"Vice Intern" +tagline:"company"
所以我的想法是我可以定义一个动态映射。由于我不提前知道这些字段的名称,这似乎是一个很好的方法。关键是提出了一种区分应该分析的字符串字段和不应该存在的字符串字段的方法!
我想,嘿,我只是将需要分析的所有字段放入嵌套对象中,如下所示:
{
"name": "bob",
"age": 22,
"title": "Vice Intern",
"textfields": {
"tagline": "Ask not what your company can do for you, but...",
"somethingelse": "lorem ipsum",
}
}
然后,在我的动态映射中,我有一种以不同方式映射这些字段的方法:
{
"mytype": {
"dynamic_templates": {
"nested_textfields": {
"match": "textfields",
"match_mapping_type": "string",
"mapping": {
"index": "analyzed",
"analyzer": "default"
}
}
}
}
}
我知道这不对,我实际上需要某种嵌套映射,但无论如何,因为如果我理解正确,即使我得到了它,它也意味着搜索这些字段(通过lucene语法)像这样:
+title:"Vice Intern" +textfields.tagline:"company"
我不想要" textfields"字首。由于我是提供包装文本字段的textfields对象的人,因此我知道其中的字段仍然在整个文档中唯一命名。
我想过使用模式匹配。因此,而不是将它们包装在" textfields"对象,我可以为它们添加前缀,例如" textfield_tagline"。但是,当这样做时,动态映射中的{name}标记包含前缀,我没有看到只是拉出" *"部分。
任何能让我获得必要行为的解决方案都是正确答案。即使这涉及到嵌套的映射信息到文档本身(你能做到吗?我认为这样的东西,我认为......)。
编辑:
我尝试过以下动态模板。我尝试使用index_name删除'文本字段。'在索引中。这个动态模板似乎并不匹配,因为在放置文档并查看映射后,我看不到指定的分析器。
{
"mytype" : {
"dynamic_templates":
[
{
"textfields": {
"path_match": "textfields.*",
"match_mapping_type" : "string",
"mapping": {
"type": "string",
"index": "analyzed",
"analyzer": "default",
"index_name": "{name}",
"fields": {
"sort": {
"type": "string",
"index": "not_analyzed",
"index_name": "{name}_sort"
}
}
}
}
}
]
}
}
答案 0 :(得分:1)
我能够通过以下索引创建(使用映射),文档和搜索查询来复制您特别要求的结果。类型确实有所不同,但它符合示例的目的。
索引设置
PUT http://localhost:9200/sandbox
{
"settings": {
"index": {
"number_of_shards": 1,
"number_of_replicas": 0
}
},
"mappings": {
"mytype": {
"dynamic_templates": [
{
"indexedfields": {
"path_match": "indexedfields.*",
"match_mapping_type" : "string",
"mapping": {
"type": "string",
"index": "analyzed",
"analyzer": "default",
"index_name": "{name}",
"fields": {
"sort": {
"type": "string",
"index": "not_analyzed",
"index_name": "{name}_sort"
}
}
}
}
},
{
"textfields": {
"path_match": "textfields.*",
"match_mapping_type" : "string",
"mapping": {
"type": "string",
"index": "not_analyzed",
"index_name": "{name}"
}
}
},
{
"strings": {
"path_match": "*",
"match_mapping_type" : "string",
"mapping": {
"type": "string",
"index": "not_analyzed"
}
}
}
]
}
}
}
<强>文档强>
PUT http://localhost:9200/sandbox/mytype/1
{
"indexedfields":{
"hello":"Hello world",
"message":"The great balls of the world are on fire"
},
"textfields":{
"username":"User Name",
"projectname":"Project Name"
}
}
搜索强>
POST http://localhost:9200/sandbox/mytype/_search
{
"query": {
"query_string": {
"query": "message:\"great balls\""
}
},
"filter":{
"query":{
"query_string":{
"query":"username:\"User Name\""
}
}
},
"from":0,
"size":10,
"sort":[
]
}
搜索返回以下响应:
{
"took":2,
"timed_out":false,
"_shards":{
"total":1,
"successful":1,
"failed":0
},
"hits":{
"total":1,
"max_score":0.19178301,
"hits":[
{
"_index":"sandbox",
"_type":"mytype",
"_id":"1",
"_score":0.19178301,
"_source":{
"indexedfields":{
"hello":"Hello world",
"message":"The great balls of the world are on fire"
},
"textfields":{
"username":"User Name",
"projectname":"Project Name"
}
}
}
]
}
}