ElasticSearch:使用复合租户ID +页面ID字段?

时间:2013-07-27 22:19:52

标签: elasticsearch multi-tenant

我刚刚为多租户网络应用设计了ElasticSearch映射。在这 应用程序,有站点ID:s和页面ID:s。页面ID:s 每个站点唯一,并随机生成。页面可以有子页面。

什么是最好的:

1)使用网站+网页ID的复合键:s?像这样:

"sitePageIdPath": "(siteID):(grandparent-page-ID).(parent-page-ID).(page-ID)"

或:

2)为网站ID和网页ID使用单独的字段?像这样:

"siteId": "(siteID)",
"pageIdPath": "(grandparent-page-ID).(parent-page-ID).(page-ID)"


我在想如果我将网站ID和页面ID合并到一个单独的字段中,那么ElasticSearch将需要仅处理 该字段,这应该比使用更高效。两个字段 - 在索引和搜索时都是如此?并且需要更少的存储空间。

然而,也许有一些我不知道的缺点?因此这个问题。

一些细节:1)我正在使用单个索引,而且我正在分配分片(100个分片),正如使用the "users" data flow pattern时所建议的那样。 2)我在URL中明确指定路由参数(即&routing=site-ID), 不是通过索引文档中的任何 siteId 字段。

7小时后更新:

1)所有查询都应按网站ID(即租户ID)进行过滤。如果我将站点ID与页面ID结合起来,我想/希望我可以使用前缀过滤器来过滤站点ID。我想知道这是否与在单个专用 siteId 字段上过滤一样快(例如,可以缓存结果)。

2)示例查询:全文搜索。列出所有用户。列出所有页面。列出某个页面的所有子页面/后继页面。加载单个页面(通过 _source )。

22小时后更新:

3)我能够按页面ID进行搜索,因为作为ElasticSearch的{​​{1}},我存储了_id。因此,将页面ID“隐藏”为 pageIdPath 的最后一个元素并不是一个问题。 我之前可能应该提到我有一个单独的页面ID字段,但我认为让问题保持简短。

4)我对这些ID字段使用(site-ID):(page-ID)

2 个答案:

答案 0 :(得分:3)

如果您使用1个字段,则在编制索引和搜索时会出现性能问题。我认为你错误地认为1提交会加快速度。

如果使用1个字段,则基本上有2个映射选项:

  1. 如果您使用默认映射,字符串(siteID):(grandparent-page-ID).(parent-page-ID).(page-ID)将被分析器分解为令牌(siteID) (grandparent-page-ID) (parent-page-ID) (page-ID) 。现在你的id就像一个单词,当你想要匹配siteID时,术语或前缀过滤器可能会从pageID中找到匹配项。

  2. 如果您设置自己的分析器(我想知道您是否能想到这样做的好方法),首先想到的是关键字(或not_analyzed)分析器。这会将字符串保留为一个标记,这样您就不会丢失上下文。 然而现在使用前缀过滤器时会有很大的性能损失。想象一下,我将字符串"123.456.789"索引为一个标记(siteID,parentpageID.pageID)。我想通过sideID = 123进行文件管理,因此我使用前缀过滤器。 As you can read here此前缀过滤器实际上已经被显示为bool个查询,其中包含所有ORed的数百个术语(123123112321233等等...),当您可以更好地构建数据时,这会大量浪费计算能力。

  3. 我建议您阅读有关lucene的PrefixQuery及其工作原理的更多信息。

    如果我是你,我会这样做。

    映射

    "properties": {
      "site_id": {
        "type": "string",
        "index": "not_analyzed" //keyword would also work here, they are basically the same
      },
      "parent_page_id": {
        "type": "string",
        "index": "not_analyzed"
      },
      "page_id": {
        "type": "string",
        "index": "not_analyzed"
      }<
      "page_content": {
        "type": "string",
        "index": "standard" //you may want to use snowball to enable stemming
      }
    }
    

    查询

    文本搜索&#34; elasticsearch教程&#34;在siteID&#34; 123&#34;

    "filtered": {
      "query": {
        "match": {
          "page_content": "elasticsearch tutorial"
        }
      },
      "filter": {
        "term": {
          "site_id": "123"
        }
      }
    }
    

    页面的所有子页面&#34; 456&#34;在网站&#34; 123&#34;

    "filtered": {
      "query": {
        "match_all": {}
      },
      "filter": {
        "and": [
          {
            "term": {
              "site_id": "123"
            }
          },
          {
            "term": {
              "parent_page_id": "456"
            }
          }
      }
    }
    

答案 1 :(得分:0)

编辑: 此答案存在问题,即可能BooleanQuery.TooManyClauses exceptions;在原始答案之后,请参阅下面的更新。的 /修改

我认为可以将网站ID和网页ID结合起来,并在查询时使用[与网站ID匹配的前缀过滤器]。我在the Query DSL docs中找到了这个信息:

  

某些过滤器已经产生易于缓存的结果,并且   缓存和不缓存它们之间的区别是行为   是否将结果放在缓存中。这些过滤器包含   术语,术语,前缀和范围过滤器

因此,结合网站ID和页面ID应该没关系w.r.t.表现我认为。我无法想到任何其他问题(请记住,按页面ID查找只是没有意义,因为如果没有网站ID,页面ID就没有任何意义。)


<强>更新

我猜 downvote 主要是 1)因为如果我将(Site-ID):(Parent-page-ID):(Page-ID)合并到一个字段中,然后尝试搜索,则存在性能问题页面ID。但是,_id字段中的页面ID可用:(site-ID):(page-ID),因此这不应该是一个问题。 (也就是说,我不只使用1个字段 - 我使用的是2个字段。)

对应于Ramseykhalaf查询的查询将是:

"filtered": {
  "query": {
    "match": {
      "page_content": "search phrase"
    }
  },
  "filter" : {
    "prefix" : {
      "_id" : "123:"    // site ID is "123"
    }
  }
}

"filtered": {
  "query": {
    "match_all": {}
  },
  "filter": {
    "and": [{
      "prefix" : {
        "_id" : "123:"  // site ID is "123"
      }, {
      "prefix": {
        "pageIdPath": "456:789:"  // section and sub section IDs are 456:789
                               // (I think I'd never search for a *subsection* only,
                               // without also knowing the parent section ID)
      }
    }]
  }
}

(我将 sitePageIdPath 重命名为 pageIdPath ,因为网站ID存储在 _id 中)


另一个2)downvote 的次要原因可能是(直到现在我才知道这一点)前缀查询被分解为与所有条款匹配的布尔查询与指定的前缀,在我的情况下,这些布尔查询可能包含非常多的术语,如果相关网站中确实有很多页面(可能有)或部分ID(没有)。那么直接使用术语查询会更快吗?并且不能导致太多子句异常(请参阅下面的链接)。

有关PrefixQuery的更多信息,请参阅:
How to improve a single character PrefixQuery performance?
With Lucene: Why do I get a Too Many Clauses error if I do a prefix search?

此布尔查询转换显然不仅适用于前缀查询,也适用于范围查询,请参阅例如Help needed figuring out reason for maxClauseCount is set to 1024 errorthe Lucene BooleanQuery.TooManyClauses docs“当尝试添加多于BooleanQuery.getMaxClauseCount()子句时抛出。如果 PrefixQuery,通常发生,在搜索“

期间,FuzzyQuery,WildcardQuery或TermRangeQuery被扩展为多个术语