-
Notifications
You must be signed in to change notification settings - Fork 27
优化了一些常见的DataFrame操作方法;优化了过滤和匹配图数据库中节点的方法 #148
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,13 +13,17 @@ import org.opencypher.v9_0.expressions.Expression | |
| */ | ||
| class DefaultDataFrameOperator(expressionEvaluator: ExpressionEvaluator) extends DataFrameOperator { | ||
|
|
||
| private def prepareColumns(df: DataFrame, columns: Seq[(String, Option[String])]): (Map[String, LynxType], Map[String, Int], Seq[Int]) = { | ||
| val sourceSchema = df.schema.toMap | ||
| val columnNameIndex = df.columnsName.zipWithIndex.toMap | ||
| val usedIndices = columns.map(_._1).map(columnNameIndex) | ||
| (sourceSchema, columnNameIndex, usedIndices) | ||
| } | ||
| override def select(df: DataFrame, columns: Seq[(String, Option[String])]): DataFrame = { | ||
| val sourceSchema: Map[String, LynxType] = df.schema.toMap | ||
| val columnNameIndex: Map[String, Int] = df.columnsName.zipWithIndex.toMap | ||
| val newSchema: Seq[(String, LynxType)] = columns.map(column => column._2.getOrElse(column._1) -> sourceSchema(column._1)) | ||
| val usedIndex: Seq[Int] = columns.map(_._1).map(columnNameIndex) | ||
| val (sourceSchema, _, usedIndices) = prepareColumns(df, columns) | ||
| val newSchema = columns.map(col => col._2.getOrElse(col._1) -> sourceSchema(col._1)) | ||
|
|
||
| DataFrame(newSchema, () => df.records.map(row => usedIndex.map(row.apply))) | ||
| DataFrame(newSchema, () => df.records.map(row => usedIndices.map(row.apply))) | ||
| } | ||
|
|
||
| override def filter(df: DataFrame, predicate: Seq[LynxValue] => Boolean)(ctx: ExpressionContext): DataFrame = | ||
|
|
@@ -42,28 +46,24 @@ class DefaultDataFrameOperator(expressionEvaluator: ExpressionEvaluator) extends | |
|
|
||
|
|
||
| override def groupBy(df: DataFrame, groupings: Seq[(String, Expression)], aggregations: Seq[(String, Expression)])(ctx: ExpressionContext): DataFrame = { | ||
| // match (n:nothislabel) return count(n) | ||
| val newSchema = (groupings ++ aggregations).map(col => | ||
| col._1 -> expressionEvaluator.typeOf(col._2, df.schema.toMap) | ||
| ) | ||
| val newSchema = (groupings ++ aggregations).map(col => col._1 -> expressionEvaluator.typeOf(col._2, df.schema.toMap)) | ||
| val columnsName = df.columnsName | ||
|
|
||
| DataFrame(newSchema, () => { | ||
| if (groupings.nonEmpty) { | ||
| df.records.map { record => | ||
| val recordCtx = ctx.withVars(columnsName.zip(record).toMap) | ||
| groupings.map(col => expressionEvaluator.eval(col._2)(recordCtx)) -> recordCtx | ||
| } // (groupingValue: Seq[LynxValue] -> recordCtx: ExpressionContext) | ||
| .toSeq.groupBy(_._1) // #group by 'groupingValue'. | ||
| .mapValues(_.map(_._2)) // #trans to: (groupingValue: Seq[LynxValue] -> recordsCtx: Seq[ExpressionContext]) | ||
| .map { case (groupingValue, recordsCtx) => // #aggragate: (groupingValues & aggregationValues): Seq[LynxValue] | ||
| groupingValue ++ { | ||
| aggregations.map { case (name, expr) => expressionEvaluator.aggregateEval(expr)(recordsCtx) } | ||
| } | ||
| }.toIterator | ||
| val groupingValues = groupings.map(col => expressionEvaluator.eval(col._2)(recordCtx)) | ||
| groupingValues -> recordCtx | ||
| }.groupBy(_._1) | ||
| .view.flatMap { case (groupingValue, records) => | ||
| Iterator(groupingValue ++ aggregations.map { case (_, expr) => | ||
| expressionEvaluator.aggregateEval(expr)(records.map(_._2)) | ||
| }) | ||
| }.iterator | ||
| } else { | ||
| val allRecordsCtx = df.records.map { record => ctx.withVars(columnsName.zip(record).toMap) }.toSeq | ||
| Iterator(aggregations.map { case (name, expr) => expressionEvaluator.aggregateEval(expr)(allRecordsCtx) }) | ||
| val allRecordsCtx = df.records.map(record => ctx.withVars(columnsName.zip(record).toMap)).toSeq | ||
| Iterator(aggregations.map { case (_, expr) => expressionEvaluator.aggregateEval(expr)(allRecordsCtx) }) | ||
| } | ||
| }) | ||
| } | ||
|
|
@@ -89,25 +89,24 @@ class DefaultDataFrameOperator(expressionEvaluator: ExpressionEvaluator) extends | |
|
|
||
| override def orderBy(df: DataFrame, sortItem: Seq[(Expression, Boolean)])(ctx: ExpressionContext): DataFrame = { | ||
| val columnsName = df.columnsName | ||
| DataFrame(df.schema, () => df.records.toSeq | ||
| .sortWith { (A, B) => | ||
| val ctxA = ctx.withVars(columnsName.zip(A).toMap) | ||
| val ctxB = ctx.withVars(columnsName.zip(B).toMap) | ||
| val sortValue = sortItem.map { | ||
| case (exp, asc) => | ||
| (expressionEvaluator.eval(exp)(ctxA), expressionEvaluator.eval(exp)(ctxB), asc) | ||
| } | ||
| _ascCmp(sortValue.toIterator) | ||
| }.toIterator) | ||
| val sortedRecords = df.records.toSeq.sortWith { (A, B) => | ||
| val ctxA = ctx.withVars(columnsName.zip(A).toMap) | ||
| val ctxB = ctx.withVars(columnsName.zip(B).toMap) | ||
| val sortValues = sortItem.map { case (exp, asc) => | ||
| val valueA = expressionEvaluator.eval(exp)(ctxA) | ||
| val valueB = expressionEvaluator.eval(exp)(ctxB) | ||
| (valueA.compareTo(valueB), asc) | ||
| } | ||
| sortValues.exists { case (cmp, asc) => cmp != 0 && (cmp > 0) == asc } | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It doesn't seem to make much sense here. Need to return asc judgement on the first different value. For example the following example: |
||
| } | ||
| DataFrame(df.schema, () => sortedRecords.iterator) | ||
| } | ||
|
|
||
| private def _ascCmp(sortValue: Iterator[(LynxValue, LynxValue, Boolean)]): Boolean = { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The function _ascCmp does not seem to be used. |
||
| while (sortValue.hasNext) { | ||
| val (valueOfA, valueOfB, asc) = sortValue.next() | ||
| sortValue.find { case (valueOfA, valueOfB, asc) => | ||
| val comparable = valueOfA.compareTo(valueOfB) | ||
| if(comparable != 0) return comparable > 0 != asc | ||
| } | ||
| false | ||
| comparable != 0 && comparable > 0 != asc | ||
| }.isDefined | ||
| } | ||
|
|
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to be just extracting these few operations, and it's not that different.