Это возможно двумя разными способами, но, вообще говоря, не рекомендуется. Сначала давайте создадим фиктивные данные:
from pyspark.sql import Row
document_row = Row("document_id", "document_text")
keyword_row = Row("keyword")
documents_df = sc.parallelize([
document_row(1L, "apache spark is the best"),
document_row(2L, "erlang rocks"),
document_row(3L, "but haskell is better")
]).toDF()
keywords_df = sc.parallelize([
keyword_row("erlang"),
keyword_row("haskell"),
keyword_row("spark")
]).toDF()
documents_df.registerTempTable("documents")
keywords_df.registerTempTable("keywords")
query = """SELECT document_id, keyword
FROM documents JOIN keywords
ON document_text LIKE CONCAT('%', keyword, '%')"""
like_with_hive_udf = sqlContext.sql(query)
like_with_hive_udf.show()
## +-----------+-------+
## |document_id|keyword|
## +-----------+-------+
## | 1| spark|
## | 2| erlang|
## | 3|haskell|
## +-----------+-------+
from pyspark.sql.functions import udf, col
from pyspark.sql.types import BooleanType
# Of you can replace `in` with a regular expression
contains = udf(lambda s, q: q in s, BooleanType())
like_with_python_udf = (documents_df.join(keywords_df)
.where(contains(col("document_text"), col("keyword")))
.select(col("document_id"), col("keyword")))
like_with_python_udf.show()
## +-----------+-------+
## |document_id|keyword|
## +-----------+-------+
## | 1| spark|
## | 2| erlang|
## | 3|haskell|
## +-----------+-------+
Почему бы не рекомендуемые? Потому что в обоих случаях для этого требуется декартово произведение:
like_with_hive_udf.explain()
## TungstenProject [document_id#2L,keyword#4]
## Filter document_text#3 LIKE concat(%,keyword#4,%)
## CartesianProduct
## Scan PhysicalRDD[document_id#2L,document_text#3]
## Scan PhysicalRDD[keyword#4]
like_with_python_udf.explain()
## TungstenProject [document_id#2L,keyword#4]
## Filter pythonUDF#13
## !BatchPythonEvaluation PythonUDF#(document_text#3,keyword#4), ...
## CartesianProduct
## Scan PhysicalRDD[document_id#2L,document_text#3]
## Scan PhysicalRDD[keyword#4]
Существуют другие способы достижения подобного эффекта без полного декартова.
from pyspark.ml.feature import Tokenizer
from pyspark.sql.functions import explode
tokenizer = Tokenizer(inputCol="document_text", outputCol="words")
tokenized = (tokenizer.transform(documents_df)
.select(col("document_id"), explode(col("words")).alias("token")))
like_with_tokenizer = (tokenized
.join(keywords_df, col("token") == col("keyword"))
.drop("token"))
like_with_tokenizer.show()
## +-----------+-------+
## |document_id|keyword|
## +-----------+-------+
## | 3|haskell|
## | 1| spark|
## | 2| erlang|
## +-----------+-------+
Для этого требуется перетасовать, но не декартово: like_with_tokenizer.explain()
## TungstenProject [document_id#2L,keyword#4]
## SortMergeJoin [token#29], [keyword#4]
## TungstenSort [token#29 ASC], false, 0
## TungstenExchange hashpartitioning(token#29)
## TungstenProject [document_id#2L,token#29]
## !Generate explode(words#27), true, false, [document_id#2L, ...
## ConvertToSafe
## TungstenProject [document_id#2L,UDF(document_text#3) AS words#27]
## Scan PhysicalRDD[document_id#2L,document_text#3]
## TungstenSort [keyword#4 ASC], false, 0
## TungstenExchange hashpartitioning(keyword#4)
## ConvertToUnsafe
## Scan PhysicalRDD[keyword#4]
from pyspark.sql.types import ArrayType, StringType
keywords = sc.broadcast(set(
keywords_df.map(lambda row: row[0]).collect()))
bd_contains = udf(
lambda s: list(set(s.split()) & keywords.value),
ArrayType(StringType()))
like_with_bd = (documents_df.select(
col("document_id"),
explode(bd_contains(col("document_text"))).alias("keyword")))
like_with_bd.show()
## +-----------+-------+
## |document_id|keyword|
## +-----------+-------+
## | 1| spark|
## | 2| erlang|
## | 3|haskell|
## +-----------+-------+
Он не требует ни перетасовки, ни декартовского языка, но вам все равно придется передавать широковещательную переменную каждому рабочему узлу. like_with_bd.explain()
## TungstenProject [document_id#2L,keyword#46]
## !Generate explode(pythonUDF#47), true, false, ...
## ConvertToSafe
## TungstenProject [document_id#2L,pythonUDF#47]
## !BatchPythonEvaluation PythonUDF#(document_text#3), ...
## Scan PhysicalRDD[document_id#2L,document_text#3]
sql.functions.broadcast
, чтобы получить аналогичный эффект, как указано выше, без использования UDF и явных переменных широковещания. Повторное использование токенизированных данных: from pyspark.sql.functions import broadcast
like_with_tokenizer_and_bd = (broadcast(tokenized)
.join(keywords_df, col("token") == col("keyword"))
.drop("token"))
like_with_tokenizer.explain()
## TungstenProject [document_id#3L,keyword#5]
## BroadcastHashJoin [token#10], [keyword#5], BuildLeft
## TungstenProject [document_id#3L,token#10]
## !Generate explode(words#8), true, false, ...
## ConvertToSafe
## TungstenProject [document_id#3L,UDF(document_text#4) AS words#8]
## Scan PhysicalRDD[document_id#3L,document_text#4]
## ConvertToUnsafe
## Scan PhysicalRDD[keyword#5]
Связано:
Можно найти Панели TimeLine здесь и здесь
И средство выбора даты и времени здесь , я лично использовал datepicker от Kevin Сумка O приемы много
Существует средство выбора даты и времени и календарь месяца на Инструментарий WPF .
После размещения вопроса я обнаружил, что django-filebrowser имеет FileBrowseWidget. С применением нескольких уродливых взломов я смог получить его, работая в django admin на ImageField и FileField (больше filebrowser.fields.FileBrowseField
не требуется на модели).
Я использую это так (с non-grappelli-dependent django-filebrowser от wardi at github), и это, кажется, работает.
# a few changes to filebrowser/fields.py
class FileBrowseWidget(Input):
...
# change the default value of attrs from None to {}
def __init__(self, attrs={}):
... # the rest unchanged
# change the default value of attrs, and the first few lines of render, like so
def render(self, name, value, attrs={}):
if value is None:
value = ""
else:
# set an attribute on value that the filebrowser templates need in
# order to display the thumbnail photo in the admin
for suffix in ['gif', 'GIF', 'jpg', 'JPG', 'png', 'PNG']:
if hasattr(value, 'path') and value.path.endswith("." + suffix):
value.filetype = "Image"
break
... # the rest unchanged
# admin.py
from filebrowser.fields import FileBrowseWidget
class FileBrowseForm(forms.ModelForm):
# Use a CharField, not an ImageField or FileField, since filebrowser
# is handling any file uploading
image = forms.CharField(required=True, widget=FileBrowseWidget())
class SomeModelAdmin(admin.ModelAdmin):
# SomeModel has an ImageField named image
form = FileBrowseForm
... # the rest of the admin definition
Это немного уродливо, но, похоже, пока работает. Он устраняет зависимость уровня модели от django-filebrowser и проталкивает зависимость к администратору, который находится там, где я хотел.
-121--3404130-Недостатком метода является то, что код-потребитель должен знать, какие ключи использовать для хранения и извлечения. Это может быть причиной ошибки, так как ключ должен быть точно правильным, или вы рискуете сохранить в неправильном месте, или получить нулевое значение назад.
Я на самом деле использую сильно типизированный вариант, поскольку я знаю, что мне нужно иметь в сессии, и, таким образом, могу настроить класс обертывания в соответствии с требованиями. У меня скорее есть дополнительный код в сеансовом классе, и не нужно беспокоиться о ключевых строках где-либо еще.
-121--4321269-Вы можете попробовать мой новый TimelineControl. Я опубликовал его в codeplex: TimelineControl
Ido.