elasticsearch

时间:2015-09-03 20:19:46

标签: php elasticsearch

我正在制定会员管理计划,因为我们希望将Elasticsearch用作搜索引擎。在这一点上,我们在索引某些字段时遇到问题,因为它们会在_all字段上产生“巨大的术语”错误。

我们的设置:

curl -XGET 'http://localhost:9200/my_index?pretty=true'
{
  "my_index" : {
    "aliases" : { },
    "mappings" : {
      "Memberships" : {
        "_all" : {
          "analyzer" : "keylower"
        },
        "properties" : {
          "Amount" : {
            "type" : "float"
          },
          "Members" : {
            "type" : "nested",
            "properties" : {
              "Startdate membership" : {
                "type" : "date",
                "format" : "dateOptionalTime"
              },
              "Enddate membership" : {
                "type" : "date",
                "format" : "dateOptionalTime"
              },
              "Members" : {
                "type" : "string",
                "analyzer" : "keylower"
              }
            }
          },
          "Membership name" : {
            "type" : "string",
            "analyzer" : "keylower"
          },
          "Description" : {
            "type" : "string",
            "analyzer" : "keylower"
          },
          "elementId" : {
            "type" : "integer"
          }
        }
      }
    },
    "settings" : {
      "index" : {
        "creation_date" : "1441310632366",
        "number_of_shards" : "1",
        "analysis" : {
          "filter" : {
            "my_char_filter" : {
              "type" : "asciifolding",
              "preserve_original" : "true"
            }
          },
          "analyzer" : {
            "keylower" : {
              "filter" : [ "lowercase", "my_char_filter" ],
              "tokenizer" : "keyword"
            }
          }
        },
        "number_of_replicas" : "1",
        "version" : {
          "created" : "1040599"
        },
        "uuid" : "nn16-9cTQ7Gn9NMBlFxHsw"
      }
    },
    "warmers" : { }
  }
}

我们使用keylower-analyzer,因为我们不希望在空格上拆分全名。这是因为我们希望能够在_all字段以及'Members'字段中搜索'john johnson'。

“会员”字段可以包含多个成员,这是问题的起点。当字段只包含几个成员时(如下例所示),没有问题。但是,该字段可能包含数百或数千个成员,这就是当我们得到immens term错误时。

curl 'http://localhost:9200/my_index/_search?pretty=true&q=*:*'
{  
   "took":1,
   "timed_out":false,
   "_shards":{  
      "total":1,
      "successful":1,
      "failed":0
   },
   "hits":{  
      "total":1,
      "max_score":1.0,
      "hits":[  
         {  
            "_index":"my_index",
            "_type":"Memberships",
            "_id":"15",
            "_score":1.0,
            "_source":{  
               "elementId":[  
                  "15"
               ],
               "Membership name":[  
                  "My membership"
               ],
               "Amount":[  
                  "100"
               ],
               "Description":[  
                  "This is the description."
               ],
               "Members":[  
                  {  
                     "Members":"John Johnson",
                     "Startdate membership":"2015-01-09",
                     "Enddate membership":"2015-09-03"
                  },
                  {  
                     "Members":"Pete Peterson",
                     "Startdate membership":"2015-09-09"
                  },
                  {  
                     "Members":"Santa Claus",
                     "Startdate membership":"2015-09-16"
                  }
               ]
            }
         }
      ]
   }
}

注意:以上示例有效!只有当“成员”字段包含(很多)更多成员时,我们才会收到错误。我们得到的错误是:

  

“error”:“IllegalArgumentException [文档至少包含一个   字段中的巨大术语= \“_ all \”(其UTF8编码长于   最大长度32766),所有这些都被跳过了。请更正   分析仪不生成这样的术语。第一个巨大的前缀   术语是:'[...] ...',原始消息:字节最多可以是32766英寸   长度;得到106807];嵌套:MaxBytesLengthExceededException [bytes可以   最多32766;得到106807]; “”状态“:500

我们只在_all-field上得到此错误,而不是在原始的Members-field上。使用ignore_above,无法再搜索fullname上的_all字段。使用标准分析器,如果我搜索'Santa Johnson',我会找到这个文件,因为_all-fields有一个标记'Santa'和'Johnson'。这就是我在这些领域使用keylower的原因。

我想要的是一个在字段上标记的分析器,但不会分解字段本身的值。现在发生的事情是整个领域的“成员”被作为一个标记,包括子场。 (所以,上面例子中的标记是:

  • 约翰逊约翰逊2015-01-09 2015-09-03皮特彼得森2015-09-09圣诞老人2015-09-16

是否有可能以这样的方式对这些字段进行标记,即每个字段都被作为单独的标记输入_all,但是不会在字段中分解它们自己的值?因此令牌将是:

  • John Johnson
  • 2015年1月9日
  • 2015年9月3日
  • Pete Peterson
  • 2015年9月9日
  • 圣诞老人
  • 2015年9月16日

注意:我们使用Elasticsearch php库。

1 个答案:

答案 0 :(得分:3)

有一种更好的方法可以做到这一点。短语搜索是否可以跨越多个字段值由position_offset_gap确定(在2.0中,它将重命名为position_increment_gap)。该参数基本上指定在一个字段的最后一个标记和以下字段的第一个标记之间应“插入”多少个字/位置。默认情况下,在2.0 position_increment_gap之前的elasticsearch中,值为0.这就是导致您描述的问题的原因。

通过合并copy_to功能并指定position_increment_gap,您可以创建一个不会出现此问题的替代my_all字段。通过在index.query.default_field设置中设置此新字段,您可以告诉elasticsearch默认情况下使用此字段,而不是在未指定字段时使用_all字段。

curl -XDELETE "localhost:9200/test-idx?pretty"
curl -XPUT "localhost:9200/test-idx?pretty" -d '{
    "settings" :{
        "index": {
            "number_of_shards": 1,
            "number_of_replicas": 0,
            "query.default_field": "my_all"
        }
    },
    "mappings": {
        "doc": {
            "_all" : {
                "enabled" : false
            },
            "properties": {
                "Members" : {
                  "type" : "nested",
                  "properties" : {
                    "Startdate membership" : {
                      "type" : "date",
                      "format" : "dateOptionalTime",
                      "copy_to": "my_all"
                    },
                    "Enddate membership" : {
                      "type" : "date",
                      "format" : "dateOptionalTime",
                      "copy_to": "my_all"
                    },
                    "Members" : {
                      "type" : "string",
                      "analyzer" : "standard",
                      "copy_to": "my_all"
                    }
                  }
                },
                "my_all" : {
                    "type": "string",
                    "position_offset_gap": 256
                }
            }
        }
    }
}'
curl -XPUT "localhost:9200/test-idx/doc/1?pretty" -d '{
    "Members": [{
        "Members": "John Johnson",
        "Startdate membership": "2015-01-09",
        "Enddate membership": "2015-09-03"
    }, {
        "Members": "Pete Peterson",
        "Startdate membership": "2015-09-09"
    }, {
        "Members": "Santa Claus",
        "Startdate membership": "2015-09-16"
    }]
}'
curl -XPOST "localhost:9200/test-idx/_refresh?pretty"
echo
echo "Should return one hit"
curl "localhost:9200/test-idx/doc/_search?pretty=true" -d '{
    "query": {
        "match_phrase" : {
            "my_all" : "John Johnson"
        }
    }
}'
echo
echo "Should return one hit"
curl "localhost:9200/test-idx/doc/_search?pretty=true" -d '{
    "query": {
        "query_string" : {
            "query" : "\"John Johnson\""
        }
    }
}'
echo
echo "Should return no hits"
curl "localhost:9200/test-idx/doc/_search?pretty=true" -d '{
    "query": {
        "match_phrase" : {
            "my_all" : "Johnson 2015-01-09"
        }
    }
}'
echo
echo "Should return no hits"
curl "localhost:9200/test-idx/doc/_search?pretty=true" -d '{
    "query": {
        "query_string" : {
            "query" : "\"Johnson 2015-01-09\""
        }
    }
}'
echo
echo "Should return no hits"
curl "localhost:9200/test-idx/doc/_search?pretty=true" -d '{
    "query": {
        "match_phrase" : {
            "my_all" : "Johnson Pete"
        }
    }
}'