3

マルチテナント Web アプリ用のElasticSearchマッピングの考案を始めたところです。このアプリには、サイト ID:s とページ ID:s があります。ページ ID: はサイトごとに一意で、ランダムに生成されます。ページには子ページを含めることができます。

最高のもの:

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 を 1 つのフィールドにマージすると、ElasticSearch はそのフィールドのみを処理する必要があると考えています。これは、 2 つのフィールドを使用するよりも、インデックス作成と検索の両方でパフォーマンスが向上するはずです。また、必要な保管スペースも少なくて済みます。

しかし、おそらく私が気付いていないいくつかの欠点がありますか?したがって、この質問。

いくつかの詳細: 1) 私は単一のインデックスを使用しており、「ユーザー」データ フロー パターンを使用するときに提案されているように、シャード (100 シャード) を過剰に割り当てています。2) インデックス付けされたドキュメントのsiteIdフィールドでは&routing=site-IDなく、URL (つまり ) でルーティング パラメータを明示的に指定しています。

7 時間後に更新:

1) すべてのクエリは、サイト ID (つまり、テナント ID) でフィルタリングする必要があります。サイト ID をページ ID と組み合わせる場合は、プレフィックス フィルターを使用してサイト ID をフィルター処理できると思います。これは、単一の専用のsiteIdフィールドでフィルタリングするのと同じくらい高速になるのでしょうか(たとえば、結果をキャッシュできますか)。

2) クエリの例: 全文検索。すべてのユーザーを一覧表示します。すべてのページを一覧表示します。特定のページのすべての子/後続ページを一覧表示します。( _source経由で) 単一のページを読み込みます。

22 時間後に更新:

3) ページ ID で検索でき_idます(site-ID):(page-ID)したがって、ページ ID がpageIdPathの最後の要素として「隠されている」ことは問題ではありません。別のページ ID フィールドがあることを先に述べておくべきだったかもしれませんが、質問は簡潔にしましょう。

4)index: not_analyzedこれらの ID フィールドに使用します。

4

2 に答える 2

3

1 つのフィールドを使用すると、インデックス作成と検索時にパフォーマンスの問題が発生します。1 個のフィールドがスピードアップすると考えているのは間違っていると思います。

1 つのフィールドを使用する場合、基本的に 2 つのマッピングの選択肢があります。

  1. デフォルトのマッピングを使用すると、文字列(siteID):(grandparent-page-ID).(parent-page-ID).(page-ID)はアナライザーによって tokens に分割され(siteID) (grandparent-page-ID) (parent-page-ID) (page-ID)ます。これで、ID は単語の袋のようなものになり、用語またはプレフィックス フィルターのいずれかが、siteID と一致させようとしているときに、pageID から一致を検出する可能性があります。

  2. 独自のアナライザーを設定する場合 (これを行う良い方法を考えられるかどうか知りたいのですが)、最初に頭に浮かぶのはキーワード (または not_analyzed) アナライザーです。これにより、文字列が1 つのトークンとして保持されるため、コンテキストが失われることはありません。ただし、プレフィックス フィルターを使用すると、パフォーマンスが大幅に低下します。文字列"123.456.789"を 1 つのトークン (siteID、parentpageID.pageID) としてインデックス付けするとします。sideID = 123 でフィルタリングしたいので、プレフィックス フィルターを使用します。ここで読むことができるように、このプレフィックス フィルターは、実際には、boolすべて OR 結合された数百の用語のクエリに展開されます (123または1231または1232または1233など...)。これは、データをより適切に構造化できる場合に、計算能力を大幅に浪費します。

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
  }
}

クエリ

siteID「123」で「elasticsearch tutorial」をテキスト検索

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

サイト「123」の下のページ「456」のすべての子ページ

"filtered": {
  "query": {
    "match_all": {}
  },
  "filter": {
    "and": [
      {
        "term": {
          "site_id": "123"
        }
      },
      {
        "term": {
          "parent_page_id": "456"
        }
      }
  }
}
于 2013-07-28T18:32:41.370 に答える
0

編集:この回答には問題があります。つまり、可能BooleanQuery.TooManyClauses exceptionsです。元の回答の後に、以下の更新を参照してください。/編集

サイト ID とページ ID を組み合わせて、[サイト ID に一致するプレフィックス フィルター] を使用してクエリを実行しても問題ないと思います。Query DSL docsでこの情報を見つけました:

一部のフィルターは、簡単にキャッシュ可能な結果を​​既に生成しており、キャッシュする場合としない場合の違いは、結果をキャッシュに入れるか入れないかです。これらのフィルターに 、term、terms、prefix、および rangeフィルターが含まれます

したがって、サイト ID とページ ID を組み合わせても、パフォーマンスに関しては問題ないと思います。また、他の問題は考えられません (ページ ID はサイト ID がなければ意味がないため、ページ ID で検索するだけでは意味がないことを覚えておいてください)。


アップデート:

1つのフィールドに結合してからページIDを検索しようとするとパフォーマンスの問題があるため、反対票は主に1)だと思います。(Site-ID):(Parent-page-ID):(Page-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)
      }
    }]
  }
}

( site-ID は_idに格納されているため、 sitePageIdPathpageIdPathに名前を変更しました)


別の 2) 反対票を投じる小さな理由は、 (これについて今まで知らなかった) プレフィックス クエリが、指定されたプレフィックスを持つすべての用語に一致するブール クエリに分割され、これらのブール クエリが私の場合に含まれる可能性があることです。関連する Web サイトに非常に多くのページ (存在する可能性がある) またはセクション ID (存在しない) がある場合、非常に多くの用語。ターム クエリを直接使用した方が速いのでしょうか。また、節が多すぎる例外が発生することはありません (以下のリンクを参照)。

PrefixQuery の詳細については、次を参照してください:
1 文字の PrefixQuery のパフォーマンスを向上させるには? および
Lucene の場合: プレフィックス検索を実行すると、Too Many Clauses エラーが発生するのはなぜですか?

この to-boolean-query 変換は、明らかにプレフィックス クエリだけでなく、範囲クエリでも発生します。たとえば、maxClauseCount が 1024 エラーに設定されている理由を理解するために必要なヘルプ、Lucene BooleanQuery.TooManyClauses ドキュメントを参照してください。 BooleanQuery.getMaxClauseCount() 節以上を追加します。これは通常、検索中にPrefixQuery 、FuzzyQuery、WildcardQuery、または TermRangeQuery が多くの用語に展開された場合に発生します"

于 2013-07-28T13:50:17.750 に答える