使用ElasticSearch中不同字段的不同查询匹配和突出显示文档

时间:2013-12-20 05:37:47

标签: elasticsearch

我的目标是创建一个查询,该查询将使用文档字段A,B和C上的正常query_string查询找到“最佳”20个文档,并尝试进行精确或精确的子集匹配例如:如果字段D是'AAA.BBB.CCC.DDD',那么对“AAA.BBB”的查询应该匹配(和“BBB.CCC”,以及“AAA.BBB.CCC”等)。哦,是的,我也希望得到突出的结果。

我最近的尝试是在字段D上使用ngram标记器/分析器,并且只允许A,B,C正常编制索引。

{
    "settings": {
        "number_of_shards": 5,
        "index": {
            "analysis": {
                "tokenizer": {
                    "customNgram": {
                        "type": "nGram",
                        "min_gram": "3",
                        "max_gram": "5"
                    }
                },
                "analyzer": {
                    "lllNgram": {
                        "type": "custom",
                        "filter": "lowercase",
                        "tokenizer": "customNgram"
                    }
                }
            }
        }
    },
    "mappings": {
        "lessons": {
            "_id": {
                "path": "id"
            },
            "properties": {
                "id": {
                    "type": "integer"
                },
                "A": {
                    "type": "string",
                    "store": "yes"
                },
                "B": {
                    "type": "string",
                    "store": "yes"
                },
                "C": {
                    "type": "string",
                    "store": "yes"
                },
                "D": {
                    "type": "string",
                    "store": "yes",
                    "analyzer": "lllNgram"
                }
            }
        }
    }
}

然后使用如下查询:

{
    "size":20,
    "query":{
        "filtered":{
            "query":{
                "match_all":{}
            },
            "filter":{
                "or":[
                    {
                        "query":{
                            "query_string":{
                                "query":"XYZZY TOP",
                                "fields":["A","B","C"]
                            }
                        }
                    },
                    {
                        "query":{
                            "match":{
                                "D": {
                                    "query":"XYZZY TOP",
                                    "operator" : "and"
                                }
                            }
                        }
                    }
                ]
            }
         }
    },
    "highlight":{
        "pre_tags":["<em>"],
        "post_tags":["<\/em>"],
        "fields":{
            "A":{},
            "B":{},
            "C":{},
            "D":{}
        }
    }
}

问题在于,D场似乎永远不会匹配任何东西......无论如何......结果集也不包含此查询的任何突出显示。

所以,请帮助我理解我在查询中做错了什么。

1 个答案:

答案 0 :(得分:8)

您的地图/查询中存在几个问题:

  • 错误的ngram大小:您定义ngram(3, 5),因此生成的术语的最大长度仅为5,并且您查询AAA.BBB(长度= 7)。它可以在您的映射中匹配,但它无效并且在这种情况下它是错误的设计(将其用于索引和搜索时出错),您可以将其扩展为ngram(3, 20)并仅将其用于索引时间。
  • 无效的映射:您不需要为索引/搜索定义ngram。相反,您可以定义index_analyzer = lllNgram,然后使用不修改search_analyzer数据的分析器,例如我的示例中的search_analyzer = keyword_lowercase_analyzer。索引数据时使用index_analyzer,因此我们需要定义规则来生成所有可能匹配的术语(在本例中为ngram),在与索引数据进行比较之前解析查询时使用search_analyzer,所以我们只是在这种情况下需要定义规则以使其保持原始状态(只是小写)
  • Inconsequence查询:为什么必须使用过滤后的查询?它将省略ES分数,但您无法获得the "best" 20 documents结果。

这是一个可行的映射/查询:

{
    "settings": {
        "number_of_shards": 5,
        "index": {
            "analysis": {
                "tokenizer": {
                    "customNgram": {
                        "type": "nGram",
                        "min_gram": "3",
                        "max_gram": "20"
                    }
                },
                "analyzer": {
                    "lllNgram": {
                        "type": "custom",
                        "filter": "lowercase",
                        "tokenizer": "customNgram"
                    },
                    "keyword_lowercase_analyzer": {
                        "tokenizer": "keyword",
                        "filter": ["lowercase"]
                    }
                }
            }
        }
    },
    "mappings": {
        "lessons": {
            "_id": {
                "path": "id"
            },
            "properties": {
                "id": {
                    "type": "integer"
                },
                "A": {
                    "type": "string",
                    "store": "yes"
                },
                "B": {
                    "type": "string",
                    "store": "yes"
                },
                "C": {
                    "type": "string",
                    "store": "yes"
                },
                "D": {
                    "type": "string",
                    "store": "yes",
                    "index" : "analyzed",
                    "index_analyzer" : "lllNgram",
                    "search_analyzer" : "keyword_lowercase_analyzer",
                    "term_vector" : "with_positions_offsets"
                }
            }
        }
    }
}

查询:

{
  "size": 20,
  "query": {
    "bool": {
      "should": [
        {
          "query_string": {
            "query": "AAA.BBB",
            "fields": [
              "A",
              "B",
              "C"
            ]
          }
        },
        {
          "match": {
            "D": {
              "query": "AAA.BBB",
              "operator": "or"
            }
          }
        }
      ]
    }
  },
  "highlight": {
    "pre_tags": [
      "<em>"
    ],
    "post_tags": [
      "</em>"
    ],
    "fields": {
      "A": {},
      "B": {},
      "C": {},
      "D": {}
    }
  }
}

注意: