在搜索中排除用户,是最佳方式

时间:2017-01-24 13:08:11

标签: elasticsearch data-structures

我有两个索引,on用于一组配置文件,另一个包含每个用户排除,例如阻止的个人资料。

每用户排除列表会经常更新,而相比之下,配置文件很少更新......在这种情况下,建议将两个索引中的数据分开,据我所知。

编辑[2017-01-25] 这是两个索引的映射:

PROFILES MAPPING

PUT xyz_profiles 
{
  "settings": { 
    "number_of_shards": 1, 
    "number_of_replicas": 0 
  },
  "mappings": {
    "profile": {
      "_all": {"enabled":false},
      "dynamic":"strict",
      "properties": {
        "profile_id":{"type":"integer"},
        "firstname": {"type":"text"},
        "age": {"type":"integer"},
        "gender":{"type":"keyword"},
        "height":{"type":"integer"},
        "area_id":{"type":"integer"},
        "created":{
          "type": "date",
          "format":"date_time_no_millis"
        },
        "location": {"type": "geo_point"}
      }
    }
  }
}

排除LISTS MAPPING

PUT xyz_exclude_from_search
{
  "settings": { 
    "auto_expand_replicas": "0-all"
  },
  "mappings": {
  "exclude_profile": {
    "_all": {"enabled":false},
    "dynamic":"strict",
    "properties": {
      "profile_id":{"type":"integer"},
      "exlude_ids":{"type":"integer"} 
    }
  }
}

number_of_shards 为1,因为它位于单个节点(我的测试服务器)上。 auto_expand_replicas 设置为0-all是为了确保将其复制到所有节点的排除列表。我知道这在单个节点上是多余的,但我不想忘记何时在生产群集上实现它。

exclude_ids 将是要从搜索中排除的整数数组(个人资料ID)。

这是搜索的一部分,其中使用当前用户排除某些配置文件(ID 3076)排除列表:

GET /xyz_profiles/profile/_search{
  "query" : {
    "bool": {
      "must_not": {
        "terms" : {
          "profile_id" : {
            "index" : "xyz_exclude_from_search",
            "type" : "exclude_profile",
            "id" : "3076",
            "path" : "exclude_ids"
          }
        }
      }
    }
  }
}

作为Elasticsearch的新手,我非常想知道这是否是最佳方式。我想在那里有一些非常有经验的人,他们可以确定我的映射或我的搜索是否遗漏了一些可以改善性能的明显事物。

例如,我还没有完全理解映射的analyze / not_analyzed部分以及在搜索中使用路由。

1 个答案:

答案 0 :(得分:1)

这是一个有趣的问题,我认为这是一种非常常见的模式,但目前在互联网上没有太多关于它的信息。

前段时间我处于类似情况,并且以与你提议的方式类似的方式解决了。但我没有将它分成两个索引,只是在我们的exclude_ids索引中添加了user字段。例如,假设当标识为1的用户正在搜索时,我们使用Term Query检查标识1是否不在目标用户exclude_ids内,查询像:

{ "term": { "exclude_ids": 1 }

使用大约200万份文件后,我发现:

  • 搜索很快

    • 考虑倒排索引如何工作我认为这种用法是正确的
    • 搜索在同一索引中完成(必须在其他索引中搜索意味着检查更多分片)
  • 更新缓慢

    • 每次向exclude_ids添加ID时,都会重新编制整个文档,因为partial updates无法使用lookup。如果exclude_ids数组变得非常长,则更新可能会变得特别慢。

    • 出于同样的原因,通常不会更新的索引数据会重新编制索引,例如姓名或年龄。

在您的情况下,因为您要在其他索引中分隔排除列表;正如您所说,通常不会更新的数据不必每次都重新编制索引。但无限期增长的阵列问题仍然存在。

另外,考虑到你进行查询的方式(我猜测使用here条款查询),过滤大量数据有可能以一些开销结束。但我不确定这一点。这是讨论issue

很难确定哪一个会通过大量数据更好地升级,进行加载测试可能是一个好主意。

解决昂贵的更新问题的一种方法可能是在{Elasticsearch中不插入exclude_ids,但只插入活动用户将列表排除在内存中(使用Redis或类似),为它们设置TTL。我认为原始数据仍然存储在MySQL中,因此可以从那里获取并在每次必要时插入内存(例如,当用户变为活动状态时)。但我认为不建议这样做,因为看起来很多术语的条款查询会大大降低性能(在question中解释)。

已经存在类似的Not Reinventing the Wheel: Email Validation in Swift,但在我看来,有许多事情需要考虑,而不是在那里说。我很乐意通过大量数据阅读更多有关搜索和更新性能的意见。