F# Weekly #46, 2013

deedle

Welcome to F# Weekly,

A roundup of F# content from this past week:

News

Video/Presentations

Blogs

That’s all for now. Ā Have a great week.

Previous F# Weekly edition – #45

F# Weekly #45, 2013

Welcome to F# Weekly,

A roundup of F# content from this past week:

News

Video/Presentations

Blogs

That’s all for now. Ā Have a great week.

Previous F# Weekly edition – #44

F# Interactive “branding”

FSI console has a pretty small font size by default. It is reallyĀ uncomfortable to share screen with projector. Ā Source code in FSI is always small and hard to read. Never thought (until today) that I can configure font, color, font size and etc. In fact, it is very easy to do:

  1. Click Tools -> Options.
  2. Select Environment -> Fonts and Colors.
  3. In the ‘Show setting for‘ drop-down select ‘F# Interactive‘.FSIbranding
  4. Here it is – you can change whatever you want.
  5. That’s wonderful!

F# Weekly #44, 2013

Welcome to F# Weekly,

A roundup of F# content from this past week:

News

Video/Presentations

Blogs

That’s all for now. Ā Have a great week.

Previous F# Weekly edition – #43

Anniversary edition of F# Weekly #43, 2013 – One year together

Weekly-1y

Deer all,

A great thing happened this time one year ago – F# Weekly was born. It seems quite recently and at the same time was long ago. Many great things happened during this time, a lot of news were spread. I would like to invite you toĀ feel the breath of nostalgia and look at first published weekly “F# Weekly #43, 2012“.

Thank you to all of you, for being withĀ me all this time. F# Community is an excellent one, I am glad to be a part of it. You are awesome andĀ it’s all thanks to you. Let’s make a small journey to the past andĀ recall some news that occurred during this time.

Small F# time journey

Of course, thereĀ happened much more than mentioned in the list. It is impossible to get all things in one small post. F# community is growing as well as a number of ongoing activities. It takes more and more time for me each week to get all news and summarize them; F# Weekly posts become longer.Ā We grow and will change the world for the better soon – be in touch with F# WeeklyĀ ;).

Finally, F# Weekly #43, aĀ roundup of F# content from this past week:

News

Video/Presentations

Blogs

That’s all for now. Ā Have a great week.

Previous F# Weekly edition – #42

Stanford CoreNLP is available on NuGet for F#/C# devs

Update (2014, January 3): Links and/or samples in this post might be outdated. The latest version of samples are available on new Stanford.NLP.NET site.

nlp-logo-navbar

Stanford CoreNLP provides a set of natural language analysis tools which can take raw English language text input and give the base forms of words, their parts of speech, whether they are names of companies, people, etc., normalize dates, times, and numeric quantities, and mark up the structure of sentences in terms of phrases and word dependencies, and indicate which noun phrases refer to the same entities. Stanford CoreNLP is an integrated framework, which make it very easy to apply a bunch of language analysis tools to a piece of text. Starting from plain text, you can run all the tools on it with just two lines of code. Its analyses provide the foundational building blocks for higher-level and domain-specific text understanding applications.

Stanford CoreNLP integrates all Stanford NLP tools, includingĀ the part-of-speech (POS) tagger,Ā the named entity recognizer (NER),Ā the parser, andĀ the coreference resolution system, and provides model files for analysis of English. The goal of this project is to enable people to quickly and painlessly get complete linguistic annotations of natural language texts. It is designed to be highly flexible and extensible. With a single option you can change which tools should be enabled and which should be disabled.

Stanford CoreNLP is here and available on NuGet. It is probably the most powerful package from wholeĀ The Stanford NLP Group software packages. Please, read usage overview on Stanford CoreNLP home page to understand what it can do, how you can configure an annotation pipeline, what steps are available for you, what models you need to have and so on.

I want to say thank you to Anonymous šŸ˜‰Ā and @OneFrameLinkĀ forĀ their contribution and stimulating me to finish this work.

Please follow next steps to get started:

Before using Stanford CoreNLP, we need to define and specify annotation pipeline. For example, annotators = tokenize, ssplit, pos, lemma, ner, parse, dcoref.

The next thing we need to do is to createĀ StanfordCoreNLP pipeline. But to instantiate a pipeline, we need to specify all required properties or at least paths to all models used by pipeline that are specified inĀ annotators string. Before starting samples, let’s define some helper function that will be used across all source code pieces: jarRootĀ is a path to folder where we extracted files from stanford-corenlp-3.2.0-models.jar; modelsRootĀ is a path to folder with all models files; ‘!’Ā is overloaded operator that converts model name to relative path to the model file.

letĀ (@@)Ā aĀ bĀ =Ā System.IO.Path.Combine(a,b)
letĀ jarRootĀ =Ā __SOURCE_DIRECTORY__Ā @@Ā @"..\..\temp\stanford-corenlp-full-2013-06-20\stanford-corenlp-3.2.0-models\"
letĀ modelsRootĀ =Ā jarRootĀ @@Ā @"edu\stanford\nlp\models\"
letĀ (!)Ā pathĀ =Ā modelsRootĀ @@Ā path

Now we are ready to instantiate the pipeline, but we need to do a small trick. Pipeline is configured to use default model files (for simplicity) and all paths are specified relatively to the root of stanford-corenlp-3.2.0-models.jar. To make things easier, we can temporary change current directory to the jarRoot, instantiate a pipeline and then change current directory back. This trick helps us dramatically decrease the number of code lines.

letĀ propsĀ =Ā Properties()
props.setProperty("annotators","tokenize,Ā ssplit,Ā pos,Ā lemma,Ā ner,Ā parse,Ā dcoref")Ā |>Ā ignore
props.setProperty("sutime.binders","0")Ā |>Ā ignore

letĀ curDirĀ =Ā System.Environment.CurrentDirectory
System.IO.Directory.SetCurrentDirectory(jarRoot)
letĀ pipelineĀ =Ā StanfordCoreNLP(props)
System.IO.Directory.SetCurrentDirectory(curDir)

However, Ā you do not have to do it. You can configure all models manually. The number of properties (especially paths to models) that you need to specify depends on the annotators value. Let’s assume for a moment that we are in Java world and we want to configure our pipeline in a custom way. Especially for this case,Ā stanford-corenlp-3.2.0-models.jar containsĀ StanfordCoreNLP.propertiesĀ (you can find it in theĀ folder with extracted files), where you can specify new property values out of code. Most of properties that we need to use for configuration are already mentioned in this file and you can easily understand what it what. But it is not enough to get it work, also you need to look into source code of Stanford CoreNLP. By the way, some days ago Stanford was moved CoreNLP source code into GitHub – now it is much easier to browse it. Ā Default paths to the models are specified inĀ DefaultPaths.java file, property keys are listed inĀ Constants.java file and information about which path match to which property name is contained inĀ Dictionaries.java. Thus, you are able to dive deeper into pipeline configuration and do whatever you want. For lazy people I already have a working sample.

letĀ propsĀ =Ā Properties()
letĀ (<==)Ā keyĀ valueĀ =Ā props.setProperty(key,Ā value)Ā |>Ā ignore
"annotators"Ā Ā Ā Ā <==Ā "tokenize,Ā ssplit,Ā pos,Ā lemma,Ā ner,Ā parse,Ā dcoref"
"pos.model"Ā Ā Ā Ā Ā <==Ā !Ā @"pos-tagger\english-bidirectional\english-bidirectional-distsim.tagger"
"ner.model"Ā Ā Ā Ā Ā <==Ā !Ā @"ner\english.all.3class.distsim.crf.ser.gz"
"parse.model"Ā Ā Ā <==Ā !Ā @"lexparser\englishPCFG.ser.gz"

"dcoref.demonym"Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā <==Ā !Ā @"dcoref\demonyms.txt"
"dcoref.states"Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā <==Ā !Ā @"dcoref\state-abbreviations.txt"
"dcoref.animate"Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā <==Ā !Ā @"dcoref\animate.unigrams.txt"
"dcoref.inanimate"Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā <==Ā !Ā @"dcoref\inanimate.unigrams.txt"
"dcoref.male"Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā <==Ā !Ā @"dcoref\male.unigrams.txt"
"dcoref.neutral"Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā <==Ā !Ā @"dcoref\neutral.unigrams.txt"
"dcoref.female"Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā <==Ā !Ā @"dcoref\female.unigrams.txt"
"dcoref.plural"Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā <==Ā !Ā @"dcoref\plural.unigrams.txt"
"dcoref.singular"Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā <==Ā !Ā @"dcoref\singular.unigrams.txt"
"dcoref.countries"Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā <==Ā !Ā @"dcoref\countries"
"dcoref.extra.gender"Ā Ā Ā Ā Ā Ā Ā <==Ā !Ā @"dcoref\namegender.combine.txt"
"dcoref.states.provinces"Ā Ā Ā <==Ā !Ā @"dcoref\statesandprovinces"
"dcoref.singleton.predictor"<==Ā !Ā @"dcoref\singleton.predictor.ser"

letĀ sutimeRulesĀ =
    [|Ā !Ā @"sutime\defs.sutime.txt";
       !Ā @"sutime\english.holidays.sutime.txt";
       !Ā @"sutime\english.sutime.txt"Ā |]
    |>Ā String.concatĀ ","
"sutime.rules"Ā Ā Ā Ā Ā Ā <==Ā sutimeRules
"sutime.binders"Ā Ā Ā Ā <==Ā "0"

letĀ pipelineĀ =Ā StanfordCoreNLP(props)

As you see, this option is much longer and harder to do. I recommend to use the first one, especially if you do not need to change the default configuration.

And now the fun part. Everything else is pretty easy: we create an annotation from your text, path it through the pipeline and interpret the results.

letĀ textĀ =Ā "KosgiĀ SantoshĀ sentĀ anĀ emailĀ toĀ StanfordĀ University.Ā HeĀ didn'tĀ getĀ aĀ reply.";

letĀ annotationĀ =Ā Annotation(text)
pipeline.annotate(annotation)
useĀ streamĀ =Ā newĀ ByteArrayOutputStream()
pipeline.prettyPrint(annotation,Ā newĀ PrintWriter(stream))
printfnĀ "%O"Ā (stream.toString())

Certainly, you can extract all processing results from annotated test.

letĀ customAnnotationPrintĀ (annotation:Annotation)Ā =
    printfnĀ "-------------"
    printfnĀ "CustomĀ print:"
    printfnĀ "-------------"
    letĀ sentencesĀ =Ā annotation.get(CoreAnnotations.SentencesAnnotation().getClass())Ā :?>Ā java.util.ArrayList
    forĀ sentenceĀ inĀ sentencesĀ |>Ā Seq.cast<CoreMap>Ā do
        printfnĀ "\n\nSentenceĀ :Ā '%O'"Ā sentence

    letĀ tokensĀ =Ā sentence.get(CoreAnnotations.TokensAnnotation().getClass())Ā :?>Ā java.util.ArrayList
    forĀ tokenĀ inĀ (tokensĀ |>Ā Seq.cast<CoreLabel>)Ā do
       letĀ wordĀ =Ā token.get(CoreAnnotations.TextAnnotation().getClass())
       letĀ posĀ Ā =Ā token.get(CoreAnnotations.PartOfSpeechAnnotation().getClass())
       letĀ nerĀ Ā =Ā token.get(CoreAnnotations.NamedEntityTagAnnotation().getClass())
       printfnĀ "%OĀ \t[pos=%O;Ā ner=%O]"Ā wordĀ posĀ ner

    printfnĀ "\nTree:"
    letĀ treeĀ =Ā sentence.get(TreeCoreAnnotations.TreeAnnotation().getClass())Ā :?>Ā Tree
    useĀ streamĀ =Ā newĀ ByteArrayOutputStream()
    tree.pennPrint(newĀ PrintWriter(stream))
    printfnĀ "TheĀ firstĀ sentenceĀ parsedĀ is:\nĀ %O"Ā (stream.toString())

    printfnĀ "\nDependencies:"
    letĀ depsĀ =Ā sentence.get(SemanticGraphCoreAnnotations.CollapsedDependenciesAnnotation().getClass())Ā :?>Ā SemanticGraph
    forĀ edgeĀ inĀ deps.edgeListSorted().toArray()Ā |>Ā Seq.cast<SemanticGraphEdge>Ā do
        letĀ govĀ =Ā edge.getGovernor()
        letĀ depĀ =Ā edge.getDependent()
        printfnĀ "%O(%s-%d,%s-%d)"
            (edge.getRelation())
            (gov.word())Ā (gov.index())
            (dep.word())Ā (dep.index())

The full code sample is available on GutHub, if you run it, you will see the following result:

Sentence #1 (9 tokens):
Kosgi Santosh sent an email to Stanford University.
[Text=Kosgi CharacterOffsetBegin=0 CharacterOffsetEnd=5 PartOfSpeech=NNP Lemma=Kosgi NamedEntityTag=PERSON] [Text=Santosh CharacterOffsetBegin=6 CharacterOffsetEnd=13 PartOfSpeech=NNP Lemma=Santosh NamedEntityTag=PERSON] [Text=sent CharacterOffsetBegin=14 CharacterOffsetEnd=18 PartOfSpeech=VBD Lemma=send NamedEntityTag=O] [Text=an CharacterOffsetBegin=19 CharacterOffsetEnd=21 PartOfSpeech=DT Lemma=a NamedEntityTag=O] [Text=email CharacterOffsetBegin=22 CharacterOffsetEnd=27 PartOfSpeech=NN Lemma=email NamedEntityTag=O] [Text=to CharacterOffsetBegin=28 CharacterOffsetEnd=30 PartOfSpeech=TO Lemma=to NamedEntityTag=O] [Text=Stanford CharacterOffsetBegin=31 CharacterOffsetEnd=39 PartOfSpeech=NNP Lemma=Stanford NamedEntityTag=ORGANIZATION] [Text=University CharacterOffsetBegin=40 CharacterOffsetEnd=50 PartOfSpeech=NNP Lemma=University NamedEntityTag=ORGANIZATION] [Text=. CharacterOffsetBegin=50 CharacterOffsetEnd=51 PartOfSpeech=. Lemma=. NamedEntityTag=O]
(ROOT
(S
(NP (NNP Kosgi) (NNP Santosh))
(VP (VBD sent)
(NP (DT an) (NN email))
(PP (TO to)
(NP (NNP Stanford) (NNP University))))
(. .)))

nn(Santosh-2, Kosgi-1)
nsubj(sent-3, Santosh-2)
root(ROOT-0, sent-3)
det(email-5, an-4)
dobj(sent-3, email-5)
nn(University-8, Stanford-7)
prep_to(sent-3, University-8)

Sentence #2 (7 tokens):
He didn’t get a reply.
[Text=He CharacterOffsetBegin=52 CharacterOffsetEnd=54 PartOfSpeech=PRP Lemma=he NamedEntityTag=O] [Text=did CharacterOffsetBegin=55 CharacterOffsetEnd=58 PartOfSpeech=VBD Lemma=do NamedEntityTag=O] [Text=n’t CharacterOffsetBegin=58 CharacterOffsetEnd=61 PartOfSpeech=RB Lemma=not NamedEntityTag=O] [Text=get CharacterOffsetBegin=62 CharacterOffsetEnd=65 PartOfSpeech=VB Lemma=get NamedEntityTag=O] [Text=a CharacterOffsetBegin=66 CharacterOffsetEnd=67 PartOfSpeech=DT Lemma=a NamedEntityTag=O] [Text=reply CharacterOffsetBegin=68 CharacterOffsetEnd=73 PartOfSpeech=NN Lemma=reply NamedEntityTag=O] [Text=. CharacterOffsetBegin=73 CharacterOffsetEnd=74 PartOfSpeech=. Lemma=. NamedEntityTag=O]
(ROOT
(S
(NP (PRP He))
(VP (VBD did) (RB n’t)
(VP (VB get)
(NP (DT a) (NN reply))))
(. .)))

nsubj(get-4, He-1)
aux(get-4, did-2)
neg(get-4, n’t-3)
root(ROOT-0, get-4)
det(reply-6, a-5)
dobj(get-4, reply-6)

Coreference set:
(2,1,[1,2)) -> (1,2,[1,3)), that is: “He” -> “Kosgi Santosh”

C# Sample

C# samples are also available on GitHub.

Stanford Temporal Tagger(SUTime)

nlp-logo-navbar

SUTime is a library for recognizing and normalizing time expressions. SUTime is available as part of the Stanford CoreNLP pipeline and can be used to annotate documents with temporal information. It is a deterministic rule-based system designed for extensibility.

There is one more useful thing that we can do with CoreNLP – time extraction. The way that we use CoreNLP is pretty similar to the previous sample. Firstly, we create an annotation pipeline and add there all required annotators. (Notice that this sample also use the operator defined at the beginning of the post)

letĀ pipelineĀ =Ā AnnotationPipeline()
pipeline.addAnnotator(PTBTokenizerAnnotator(false))
pipeline.addAnnotator(WordsToSentencesAnnotator(false))

letĀ taggerĀ =Ā MaxentTagger(!Ā @"pos-tagger\english-bidirectional\english-bidirectional-distsim.tagger")
pipeline.addAnnotator(POSTaggerAnnotator(tagger))

letĀ sutimeRulesĀ =
    [|Ā !Ā @"sutime\defs.sutime.txt";
       !Ā @"sutime\english.holidays.sutime.txt";
       !Ā @"sutime\english.sutime.txt"Ā |]
    |>Ā String.concatĀ ","
letĀ propsĀ =Ā Properties()
props.setProperty("sutime.rules",Ā sutimeRulesĀ )Ā |>Ā ignore
props.setProperty("sutime.binders",Ā "0")Ā |>Ā ignore
pipeline.addAnnotator(TimeAnnotator("sutime",Ā props))

Now we are ready to annotate something. This part is also equal to the same one from the previous sample.

letĀ textĀ =Ā "ThreeĀ interestingĀ datesĀ areĀ 18Ā FebĀ 1997,Ā theĀ 20thĀ ofĀ julyĀ andĀ 4Ā daysĀ fromĀ today."
letĀ annotationĀ =Ā Annotation(text)
annotation.set(CoreAnnotations.DocDateAnnotation().getClass(),Ā "2013-07-14")Ā |>Ā ignore
pipeline.annotate(annotation)

And finally, we need to interpret annotating results.

printfnĀ "%O\n"Ā (annotation.get(CoreAnnotations.TextAnnotation().getClass()))
letĀ timexAnnsAllĀ =Ā annotation.get(TimeAnnotations.TimexAnnotations().getClass())Ā :?>Ā java.util.ArrayList
forĀ cmĀ inĀ timexAnnsAllĀ |>Ā Seq.cast<CoreMap>Ā do
    letĀ tokensĀ =Ā cm.get(CoreAnnotations.TokensAnnotation().getClass())Ā :?>Ā java.util.List
    letĀ firstĀ =Ā tokens.get(0)
    letĀ lastĀ =Ā tokens.get(tokens.size()Ā -Ā 1)
    letĀ timeĀ =Ā cm.get(TimeExpression.Annotation().getClass())Ā :?>Ā TimeExpression
    printfnĀ "%AĀ [fromĀ charĀ offsetĀ '%A'Ā toĀ '%A']Ā -->Ā %A"
        cmĀ firstĀ lastĀ (time.getTemporal())

The full code sample is available on GutHub, if you run it you will see the following result:

18 Feb 1997 [from char offset ’18’ to ‘1997’] –> 1997-2-18
the 20th of july [from char offset ‘the’ to ‘July’] –> XXXX-7-20
4 days from today [from char offset ‘4’ to ‘today’] –> THIS P1D OFFSET P4D

C# Sample

C# samples are also available on GitHub.

Conclusion

There is a pretty awesome library. I hope you enjoy it. Try it out right now!

There are some other more specific Stanford packages that are already available on NuGet:

FAST Search Server 2010 for SharePoint Versions

Talbott Crowell's avatarTalbott Crowell's Software Development Blog

Here is a table that contains a comprehensive list of FAST Search Server 2010 for SharePoint versions including RTM, cumulative updates (CU’s), and hotfixes. Please let me know if you find any errors or have a version not listed here by using the comments.

BuildReleaseComponentInformationSource (Link to Download)
14.0.4763.1000RTMFAST Search ServerMark Ā  van DijkĀ 
14.0.5128.5001October 2010 CUFAST Search ServerKB2449730Mark Ā  van DijkĀ 
14.0.5136.5000February 2011 CUFAST Search ServerKB2504136Mark Ā  van DijkĀ 
14.0.6029.1000Service Pack 1FAST Search ServerKB2460039Todd Ā  Klindt
14.0.6109.5000August 2011 CUFAST Search ServerKB2553040Todd Ā  Klindt
14.0.6117.5002February 2012 CUFAST Search ServerKB2597131Todd Ā  Klindt
14.0.6120.5000April 2012 CUFAST Search ServerKB2598329Todd Ā  Klindt
14.0.6126.5000August 2012 CUFAST Search ServerKB2687489Mark Ā  van DijkĀ 
14.0.6129.5000October 2012 CUFAST Search ServerKB2760395Todd…

View original post 245 more words

F# Weekly #42, 2013

Welcome to F# Weekly,

A roundup of F# content from this past week:

News

Video/Presentations

Blogs

That’s all for now. Ā Have a great week.

Previous F# Weekly edition – #41