弹性搜索完成类型中的特殊字符

时间:2015-02-28 19:09:12

标签: autocomplete elasticsearch

我是弹性搜索的新用户,我有一个映射: -

curl -X PUT localhost:9200/vee_trade -d '
{
 "mappings": {
  "sDocument" : {
   "properties" : {
    "id" : { "type" : "long" },
    "docId" : { "type" : "string" },
    "documentType" : { "type" : "string" },
    "rating"  : { "type" : "float" },
    "suggestion" : { "type" :     "completion"}
    }
   }
  }
}

并且一个样本数据是: -

 _index: "test"
 _type: "sDocument"
 _id: "CATEGORY7"
 _score: 1
 _source{}
 docId: "CATEGORY7"
 documentType: "CATEGORY"
 id: 7
 suggestion[]
 "Kids's wear"
 rating: null

基本上我的目标是启用自动建议,这适用于查询但在自动建议条目中我只获得术语和分数值,而我还想要其他字段值, 所以我再次使用结果自动建议的术语

对建议字段进行匹配查询
{
  "query" : {
   "match" : {
    "suggestion" : "Men's"  
    }
   }
}

但我没有获取数据,因为弹性从术语中删除了特殊字符(不确定它是如何存储和索引的)所以请告诉我

如何在auto建议中检索其他字段值以及搜索词?或如何使匹配查询工作???

提前致谢。

1 个答案:

答案 0 :(得分:0)

警告:答案很长。从你发布的内容中确切地说出问题是有点困难,所以我给你提供了几个可供探索的选项,可能有助于解决你的问题。

您可以通过几种不同的方式了解您的目标。我在Qbox blog上写了两种不同的自动填充方法,一篇关于使用completion suggest的帖子和一篇关于使用涉及ngrams and multiple fields的更复杂设置的文章。

我发现完成建议在实践中有点笨拙(因为你必须明确告诉它应该做什么),所以我倾向于更多地依赖自定义分析框架。您可以尝试使用分析器的一种方法是为属性设置多个sub-fields(以前称为多字段)。所以我将在下面展示几个例子。

我将设置一个包含几个子字段的字段,以不同的方式分析文本,然后在每个字段上使用match查询来显示其行为。

看看这个:

PUT /test_index
{
   "settings": {
      "number_of_shards": 1,
      "analysis": {
         "filter": {
            "nGram_filter": {
               "type": "nGram",
               "min_gram": 2,
               "max_gram": 20,
               "token_chars": [
                  "letter",
                  "digit",
                  "punctuation",
                  "symbol"
               ]
            }
         },
         "analyzer": {
            "nGram_analyzer": {
               "type": "custom",
               "tokenizer": "whitespace",
               "filter": [
                  "lowercase",
                  "asciifolding",
                  "nGram_filter"
               ]
            },
            "whitespace_analyzer": {
               "type": "custom",
               "tokenizer": "whitespace",
               "filter": [
                  "lowercase",
                  "asciifolding"
               ]
            }
         }
      }
   },
   "mappings": {
      "doc": {
         "properties": {
            "text_field": {
               "type": "string",
               "index_analyzer": "standard",
               "search_analyzer": "standard",
               "fields": {
                  "raw": {
                     "type": "string",
                     "index": "not_analyzed"
                  },
                  "ngram": {
                     "type": "string",
                     "index_analyzer": "nGram_analyzer",
                     "search_analyzer": "whitespace_analyzer"
                  }
               }
            }
         }
      }
   }
}

这里有很多内容,我建议您阅读analysisngrams。另外,我从我的partial-word autocomplete post中获取了部分代码,因此您可能会发现通过该代码进行更全面的解释会很有帮助。

但基本上,我有一个字段"text_field",使用"standard" analyzer进行分析,两者都用于索引(即,在创建倒排索引时为给定文档和字段生成的术语),以及搜索(搜索短语被分解为与倒排索引中的术语匹配的术语的方式)。然后我在该字段上有两个不同的子字段。一个根本没有分析,因此我们可以匹配的唯一术语将是文档字段的原始文本。使用"nGram_analyzer"进行索引分析第二个子字段,使用"whitespace_analyzer"进行搜索,这两个子字段都在索引的"settings"中定义。

现在,如果我们索引几个文件:

PUT /test_index/doc/1
{
    "text_field": "Kid's wear"
}

PUT /test_index/doc/2
{
    "text_field": "Men's wear"
}

我们可以通过各种方式搜索它们。

查询"text_field.raw"将需要完整的全文才能获得匹配:

POST /test_index/doc/_search
{
   "query": {
      "match": {
         "text_field.raw": "Men's wear"
      }
   }
}
{
   "took": 1,
   "timed_out": false,
   "_shards": {
      "total": 1,
      "successful": 1,
      "failed": 0
   },
   "hits": {
      "total": 1,
      "max_score": 1,
      "hits": [
         {
            "_index": "test_index",
            "_type": "doc",
            "_id": "2",
            "_score": 1,
            "_source": {
               "text_field": "Men's wear"
            }
         }
      ]
   }
}

针对"match"的标准"text_field"查询按预期工作,因为术语"Men's"将在索引和搜索时被标记为"men"

POST /test_index/doc/_search
{
   "query": {
      "match": {
         "text_field": "Men's"
      }
   }
}
...
{
   "took": 1,
   "timed_out": false,
   "_shards": {
      "total": 1,
      "successful": 1,
      "failed": 0
   },
   "hits": {
      "total": 1,
      "max_score": 0.625,
      "hits": [
         {
            "_index": "test_index",
            "_type": "doc",
            "_id": "2",
            "_score": 0.625,
            "_source": {
               "text_field": "Men's wear"
            }
         }
      ]
   }
}

但如果我们添加第二个术语,我们会得到可能不是我们想要的结果:

POST /test_index/doc/_search
{
   "query": {
      "match": {
         "text_field": "Men's wear"
      }
   }
}
...
{
   "took": 1,
   "timed_out": false,
   "_shards": {
      "total": 1,
      "successful": 1,
      "failed": 0
   },
   "hits": {
      "total": 2,
      "max_score": 0.72711754,
      "hits": [
         {
            "_index": "test_index",
            "_type": "doc",
            "_id": "2",
            "_score": 0.72711754,
            "_source": {
               "text_field": "Men's wear"
            }
         },
         {
            "_index": "test_index",
            "_type": "doc",
            "_id": "1",
            "_score": 0.09494676,
            "_source": {
               "text_field": "Kid's wear"
            }
         }
      ]
   }
}

这是因为生成术语的方式,并且因为匹配查询的默认运算符是"or"。我们可以通过指定匹配查询使用的operator "and"来限制结果:

POST /test_index/doc/_search
{
   "query": {
      "match": {
         "text_field": {
             "query":  "Men's wear",
             "operator": "and"
         }
      }
   }
}
...
{
   "took": 2,
   "timed_out": false,
   "_shards": {
      "total": 1,
      "successful": 1,
      "failed": 0
   },
   "hits": {
      "total": 1,
      "max_score": 0.72711754,
      "hits": [
         {
            "_index": "test_index",
            "_type": "doc",
            "_id": "2",
            "_score": 0.72711754,
            "_source": {
               "text_field": "Men's wear"
            }
         }
      ]
   }
}

我们可以使用"text_field.ngram"字段匹配部分字词(包括符号和标点符号,因为我们的索引设置中"nGram_filter"的定义中指定了这一点):

POST /test_index/doc/_search
{
   "query": {
      "match": {
         "text_field.ngram": {
             "query":  "men's we",
             "operator": "and"
         }
      }
   }
}
...
{
   "took": 2,
   "timed_out": false,
   "_shards": {
      "total": 1,
      "successful": 1,
      "failed": 0
   },
   "hits": {
      "total": 1,
      "max_score": 0.72711754,
      "hits": [
         {
            "_index": "test_index",
            "_type": "doc",
            "_id": "2",
            "_score": 0.72711754,
            "_source": {
               "text_field": "Men's wear"
            }
         }
      ]
   }
}

希望这会给你一些关于如何继续的想法。